diff --git a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java index d6294f8..a5f769d 100644 --- a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java +++ b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java @@ -17,6 +17,7 @@ package org.springframework.session.data.gemfire; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.ArrayUtils.asArray; import java.io.File; import java.io.IOException; @@ -25,9 +26,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; -import java.util.Collections; import java.util.Date; -import java.util.Properties; import java.util.concurrent.TimeUnit; import org.junit.After; @@ -37,9 +36,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -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.client.ClientCache; @@ -51,10 +48,10 @@ 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.config.annotation.CacheServerApplication; +import org.springframework.data.gemfire.config.annotation.CacheServerConfigurer; +import org.springframework.data.gemfire.config.annotation.ClientCacheApplication; +import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer; import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.session.Session; import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession; @@ -71,31 +68,36 @@ import org.springframework.util.FileSystemUtils; import org.springframework.util.SocketUtils; /** - * Integration tests to test the functionality of GemFire-backed Spring Sessions using - * the GemFire client-server topology. + * Integration tests testing the functionality of Apache Geode / Pivotal 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.Session - * @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 + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication + * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication + * @see org.springframework.session.Session + * @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.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.SpringRunner + * @see org.springframework.test.context.web.WebAppConfiguration */ @RunWith(SpringRunner.class) @ContextConfiguration(classes = - ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionDataGemFireClientConfiguration.class) + ClientServerGemFireOperationsSessionRepositoryIntegrationTests.TestGemFireClientConfiguration.class) @DirtiesContext @WebAppConfiguration public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests @@ -109,9 +111,10 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests private static Process gemfireServer; - private static final String SPRING_SESSION_GEMFIRE_REGION_NAME = "TestClientServerSessions"; + private static final String TEST_SESSION_REGION_NAME = "TestClientServerSessions"; @Autowired + @SuppressWarnings("all") private SessionEventListener sessionEventListener; @BeforeClass @@ -122,7 +125,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests 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); + TestGemFireServerConfiguration.SERVER_HOSTNAME, port); System.setProperty("spring.session.data.gemfire.port", String.valueOf(port)); @@ -131,10 +134,10 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests processWorkingDirectory = createDirectory(processWorkingDirectoryPathname); - gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory, + gemfireServer = run(TestGemFireServerConfiguration.class, processWorkingDirectory, String.format("-Dspring.session.data.gemfire.port=%1$d", port)); - assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)) + assertThat(waitForCacheServerToStart(TestGemFireServerConfiguration.SERVER_HOSTNAME, port)) .isTrue(); System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0); @@ -164,7 +167,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests assertThat(GemFireUtils.isClient(gemfireCache)).isTrue(); Region springSessionGemFireRegion = - gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME); + gemfireCache.getRegion(TEST_SESSION_REGION_NAME); assertThat(springSessionGemFireRegion).isNotNull(); @@ -257,53 +260,25 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests assertThat(deletedSession).isNull(); } - @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, + @ClientCacheApplication(logLevel = "warning", pingInterval = 5000, readTimeout = 2500, retryAttempts = 1, + subscriptionEnabled = true) + @EnableGemFireHttpSession(regionName = TEST_SESSION_REGION_NAME, poolName = "DEFAULT", clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) @SuppressWarnings("unused") - static class SpringSessionDataGemFireClientConfiguration { + static class TestGemFireClientConfiguration { @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( + ClientCacheConfigurer clientCacheDefaultPoolPortConfigurer( @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; + return (beanName, clientCacheFactoryBean) -> + clientCacheFactoryBean.setServers(asArray(new ConnectionEndpoint("localhost", port))); } @Bean @@ -316,7 +291,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests public static void main(String[] args) { ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext( - SpringSessionDataGemFireClientConfiguration.class); + TestGemFireClientConfiguration.class); applicationContext.registerShutdownHook(); @@ -329,10 +304,12 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests } } - @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, + @CacheServerApplication(name = "ClientServerGemFireOperationsSessionRepositoryIntegrationTests", + logLevel = "warning") + @EnableGemFireHttpSession(regionName = TEST_SESSION_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) @SuppressWarnings("unused") - static class SpringSessionDataGemFireServerConfiguration { + static class TestGemFireServerConfiguration { static final String SERVER_HOSTNAME = "localhost"; @@ -341,53 +318,20 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests 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(GemFireCache gemfireCache, + CacheServerConfigurer cacheServerPortConfigurer( @Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) { - CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean(); - - cacheServerFactory.setCache((Cache) gemfireCache); - cacheServerFactory.setAutoStartup(true); - cacheServerFactory.setBindAddress(SERVER_HOSTNAME); - cacheServerFactory.setPort(port); - - return cacheServerFactory; + return (beanName, cacheServerFactoryBean) -> cacheServerFactoryBean.setPort(port); } @SuppressWarnings("resource") public static void main(String[] args) throws IOException { - AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class); + AnnotationConfigApplicationContext applicationContext = + new AnnotationConfigApplicationContext(TestGemFireServerConfiguration.class); - context.registerShutdownHook(); + applicationContext.registerShutdownHook(); writeProcessControlFile(WORKING_DIRECTORY); } diff --git a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryIntegrationTests.java b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryIntegrationTests.java index e210436..307bc4c 100644 --- a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryIntegrationTests.java +++ b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryIntegrationTests.java @@ -48,29 +48,33 @@ import org.springframework.session.Session; 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.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** - * Integration test to test the {@code findByPrincipalName} query method - * on {@link GemFireOperationsSessionRepository}. + * 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.apache.geode.cache.Region + * @see org.apache.geode.cache.query.QueryService + * @see org.apache.geode.pdx.PdxSerializable + * @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication + * @see org.springframework.security.core.context.SecurityContext + * @see org.springframework.session.Session * @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests * @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository + * @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession * @see org.springframework.test.annotation.DirtiesContext * @see org.springframework.test.context.ContextConfiguration - * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @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 */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration @DirtiesContext @WebAppConfiguration @@ -328,8 +332,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract ((AbstractGemFireOperationsSessionRepository.GemFireSession) expectedSession).setPrincipalName("jblum"); - List expectedAttributeNames = Arrays.asList("booleanAttribute", "numericAttribute", "stringAttribute", - "personAttribute"); + List expectedAttributeNames = + Arrays.asList("booleanAttribute", "numericAttribute", "stringAttribute", "personAttribute"); Person jonDoe = new Person("Jon", "Doe"); @@ -406,13 +410,13 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract pdxWriter.writeString("lastName", getLastName()); } - public void fromData(final PdxReader pdxReader) { + public void fromData(PdxReader pdxReader) { this.firstName = pdxReader.readString("firstName"); this.lastName = pdxReader.readString("lastName"); } @SuppressWarnings("all") - public int compareTo(final Person person) { + public int compareTo(Person person) { int compareValue = getLastName().compareTo(person.getLastName()); @@ -420,7 +424,7 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract } @Override - public boolean equals(final Object obj) { + public boolean equals(Object obj) { if (this == obj) { return true; diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java index 73f51aa..110a016 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java @@ -16,6 +16,8 @@ package org.springframework.session.data.gemfire; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -32,6 +34,7 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.geode.DataSerializable; import org.apache.geode.DataSerializer; @@ -93,7 +96,7 @@ import org.apache.commons.logging.LogFactory; public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter implements ApplicationEventPublisherAware, FindByIndexNameSessionRepository, InitializingBean { - private boolean usingDataSerialization = false; + private static final AtomicBoolean usingDataSerialization = new AtomicBoolean(false); private ApplicationEventPublisher applicationEventPublisher = new ApplicationEventPublisher() { @@ -246,7 +249,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi * @param useDataSerialization boolean indicating whether the DataSerialization framework has been configured. */ public void setUseDataSerialization(boolean useDataSerialization) { - this.usingDataSerialization = useDataSerialization; + usingDataSerialization.set(useDataSerialization); } /** @@ -254,8 +257,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi * * @return a boolean indicating whether the DataSerialization framework has been configured. */ - protected boolean isUsingDataSerialization() { - return this.usingDataSerialization; + protected static boolean isUsingDataSerialization() { + return usingDataSerialization.get(); } /** @@ -292,9 +295,6 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi this.fullyQualifiedRegionName = region.getFullPath(); region.getAttributesMutator().addCacheListener(this); - - Instantiator.register(GemFireSessionInstantiator.create()); - Instantiator.register(GemFireSessionAttributesInstantiator.create()); } /* (non-Javadoc) */ @@ -524,22 +524,57 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi return session; } + @SuppressWarnings("unused") + public static class DeltaCapableGemFireSession extends GemFireSession + implements Delta { + + public DeltaCapableGemFireSession() { } + + public DeltaCapableGemFireSession(String id) { + super(id); + } + + public DeltaCapableGemFireSession(Session session) { + super(session); + } + + @Override + protected DeltaCapableGemFireSessionAttributes newSessionAttributes(Object lock) { + return new DeltaCapableGemFireSessionAttributes(); + } + + /* (non-Javadoc) */ + public synchronized void toDelta(DataOutput out) throws IOException { + + out.writeUTF(getId()); + out.writeLong(getLastAccessedTime().toEpochMilli()); + out.writeLong(getMaxInactiveInterval().getSeconds()); + getAttributes().toDelta(out); + clearDelta(); + } + + /* (non-Javadoc) */ + public synchronized void fromDelta(DataInput in) throws IOException { + + setId(in.readUTF()); + setLastAccessedTime(Instant.ofEpochMilli(in.readLong())); + setMaxInactiveInterval(Duration.ofSeconds(in.readLong())); + getAttributes().fromDelta(in); + clearDelta(); + } + } + /** - * {@link GemFireSession} is a GemFire model for a Spring {@link Session} that stores and manages {@link Session} - * state in GemFire. This class implements GemFire's {@link DataSerializable} interface to better handle - * replication of {@link Session} state across the GemFire cluster. + * {@link GemFireSession} is a Abstract Data Type (ADT) for a Spring {@link Session} that stores and manages + * {@link Session} state in Apache Geode or Pivotal GemFire. * * @see java.lang.Comparable - * @see org.apache.geode.DataSerializable - * @see org.apache.geode.Delta * @see org.springframework.session.Session */ @SuppressWarnings("serial") - public static class GemFireSession implements Comparable, DataSerializable, Delta, Session { + public static class GemFireSession implements Comparable, Session { - protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true; - - private static final Duration DEFAULT_MAX_INACTIVE_INTERVAL = Duration.ZERO; + protected static final Duration DEFAULT_MAX_INACTIVE_INTERVAL = Duration.ZERO; protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; @@ -547,8 +582,6 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi private Duration maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL; - private transient final GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(this); - private Instant creationTime; private Instant lastAccessedTime; @@ -556,6 +589,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi private String id; + private transient final T sessionAttributes = newSessionAttributes(this); + /* (non-Javadoc) */ protected GemFireSession() { this(generateId()); @@ -582,13 +617,19 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi /* (non-Javadoc) */ public static GemFireSession copy(Session session) { - return new GemFireSession(session); + return (isUsingDataSerialization() ? new DeltaCapableGemFireSession(session) : new GemFireSession(session)); + } + + /* (non-Javadoc) */ + public static GemFireSession create() { + return create(DEFAULT_MAX_INACTIVE_INTERVAL); } /* (non-Javadoc) */ public static GemFireSession create(Duration maxInactiveInterval) { - GemFireSession session = new GemFireSession(); + GemFireSession session = + (isUsingDataSerialization() ? new DeltaCapableGemFireSession() : new GemFireSession()); session.setMaxInactiveInterval(maxInactiveInterval); @@ -596,8 +637,9 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi } /* (non-Javadoc) */ - public static GemFireSession from(Session session) { - return (session instanceof GemFireSession ? (GemFireSession) session : copy(session)); + @SuppressWarnings("unchecked") + public static T from(Session session) { + return (T) (session instanceof GemFireSession ? (GemFireSession) session : copy(session)); } /** @@ -612,32 +654,53 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi /* (non-Javadoc) */ private static String validateId(String id) { - return Optional.ofNullable(id).filter(StringUtils::hasText) - .orElseThrow(() -> new IllegalArgumentException("ID is required")); + .orElseThrow(() -> newIllegalArgumentException("ID is required")); + } + + @SuppressWarnings("unchecked") + protected T newSessionAttributes(Object lock) { + return (T) new GemFireSessionAttributes(lock); } /* (non-Javadoc) */ - protected boolean allowJavaSerialization() { - return DEFAULT_ALLOW_JAVA_SERIALIZATION; - } - @Override public synchronized String changeSessionId() { this.id = generateId(); + triggerDelta(); return getId(); } /* (non-Javadoc) */ - public synchronized String getId() { - return this.id; + public synchronized void clearDelta() { + this.delta = false; } /* (non-Javadoc) */ - public synchronized Instant getCreationTime() { - return this.creationTime; + public synchronized boolean hasDelta() { + return (this.delta || this.sessionAttributes.hasDelta()); + } + + /* (non-Javadoc) */ + @SuppressWarnings("unused") + protected void triggerDelta() { + triggerDelta(true); + } + + /* (non-Javadoc) */ + protected synchronized void triggerDelta(boolean condition) { + this.delta |= condition; + } + + synchronized void setId(String id) { + this.id = validateId(id); + } + + /* (non-Javadoc) */ + public synchronized String getId() { + return this.id; } /* (non-Javadoc) */ @@ -661,10 +724,15 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi } /* (non-Javadoc) */ - public GemFireSessionAttributes getAttributes() { + public T getAttributes() { return this.sessionAttributes; } + /* (non-Javadoc) */ + public synchronized Instant getCreationTime() { + return this.creationTime; + } + /* (non-Javadoc) */ public synchronized boolean isExpired() { @@ -688,7 +756,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi /* (non-Javadoc) */ public synchronized void setLastAccessedTime(Instant lastAccessedTime) { - this.delta |= !ObjectUtils.nullSafeEquals(this.lastAccessedTime, lastAccessedTime); + triggerDelta(!ObjectUtils.nullSafeEquals(this.lastAccessedTime, lastAccessedTime)); this.lastAccessedTime = lastAccessedTime; } @@ -699,7 +767,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi /* (non-Javadoc) */ public synchronized void setMaxInactiveInterval(Duration maxInactiveIntervalInSeconds) { - this.delta |= !ObjectUtils.nullSafeEquals(this.maxInactiveInterval, maxInactiveIntervalInSeconds); + triggerDelta(!ObjectUtils.nullSafeEquals(this.maxInactiveInterval, maxInactiveIntervalInSeconds)); this.maxInactiveInterval = maxInactiveIntervalInSeconds; } @@ -733,79 +801,6 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi return principalName; } - /* (non-Javadoc) */ - public synchronized void toData(DataOutput out) throws IOException { - - out.writeUTF(getId()); - out.writeLong(getCreationTime().toEpochMilli()); - out.writeLong(getLastAccessedTime().toEpochMilli()); - out.writeLong(getMaxInactiveInterval().getSeconds()); - - 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 = Instant.ofEpochMilli(in.readLong()); - setLastAccessedTime(Instant.ofEpochMilli(in.readLong())); - setMaxInactiveInterval(Duration.ofSeconds(in.readLong())); - - int principalNameLength = in.readInt(); - - if (principalNameLength > 0) { - setPrincipalName(in.readUTF()); - } - - this.sessionAttributes.from(this.readObject(in)); - - this.delta = false; - } - - /* (non-Javadoc) */ - 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().toEpochMilli()); - out.writeLong(getMaxInactiveInterval().getSeconds()); - getAttributes().toDelta(out); - this.delta = false; - } - - /* (non-Javadoc) */ - public synchronized void fromDelta(DataInput in) throws IOException { - setLastAccessedTime(Instant.ofEpochMilli(in.readLong())); - setMaxInactiveInterval(Duration.ofSeconds(in.readLong())); - getAttributes().fromDelta(in); - this.delta = false; - } - /* (non-Javadoc) */ @SuppressWarnings("all") public int compareTo(Session session) { @@ -851,24 +846,120 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi } } - /** - * 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 { + @SuppressWarnings("unused") + public static class DeltaCapableGemFireSessionAttributes extends GemFireSessionAttributes implements Delta { - public static GemFireSessionInstantiator create() { - return new GemFireSessionInstantiator(GemFireSession.class, 800813552); + private transient final Map sessionAttributeDeltas = new HashMap<>(); + + public DeltaCapableGemFireSessionAttributes() { } - public GemFireSessionInstantiator(Class type, int id) { - super(type, id); + public DeltaCapableGemFireSessionAttributes(Object lock) { + super(lock); } + /* (non-Javadoc) */ + public Object setAttribute(String attributeName, Object attributeValue) { + + synchronized (getLock()) { + + if (attributeValue != null) { + + Object previousAttributeValue = super.setAttribute(attributeName, attributeValue); + + if (!attributeValue.equals(previousAttributeValue)) { + this.sessionAttributeDeltas.put(attributeName, attributeValue); + } + + return previousAttributeValue; + } + else { + return removeAttribute(attributeName); + } + } + } + + /* (non-Javadoc) */ @Override - public DataSerializable newInstance() { - return new GemFireSession(); + public Object removeAttribute(String attributeName) { + + synchronized (getLock()) { + + return Optional.ofNullable(super.removeAttribute(attributeName)) + .map(previousAttributeValue -> { + this.sessionAttributeDeltas.put(attributeName, null); + return previousAttributeValue; + }) + .orElse(null); + } + } + + /* (non-Javadoc) */ + public void toDelta(DataOutput out) throws IOException { + + synchronized (getLock()) { + + out.writeInt(this.sessionAttributeDeltas.size()); + + for (Map.Entry entry : this.sessionAttributeDeltas.entrySet()) { + out.writeUTF(entry.getKey()); + writeObject(entry.getValue(), out); + } + + clearDelta(); + } + } + + /* (non-Javadoc) */ + protected void writeObject(Object value, DataOutput out) throws IOException { + DataSerializer.writeObject(value, out); + } + + /* (non-Javadoc) */ + @Override + public boolean hasDelta() { + + synchronized (getLock()) { + return !this.sessionAttributeDeltas.isEmpty(); + } + } + + /* (non-Javadoc) */ + public void fromDelta(DataInput in) throws InvalidDeltaException, IOException { + + synchronized (getLock()) { + try { + int count = in.readInt(); + + Map deltas = new HashMap<>(count); + + while (count-- > 0) { + deltas.put(in.readUTF(), readObject(in)); + } + + deltas.forEach((key, value) -> { + setAttribute(key, value); + this.sessionAttributeDeltas.remove(key); + }); + } + catch (ClassNotFoundException cause) { + throw new InvalidDeltaException("Class type in data not found", cause); + } + } + } + + /* (non-Javadoc) */ + protected T readObject(DataInput in) throws ClassNotFoundException, IOException { + return DataSerializer.readObject(in); + } + + /* (non-Javadoc) */ + @Override + public void clearDelta() { + + synchronized (getLock()) { + this.sessionAttributeDeltas.clear(); + } } } @@ -885,13 +976,9 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi * @see org.apache.geode.Delta */ @SuppressWarnings("serial") - public static class GemFireSessionAttributes extends AbstractMap - implements DataSerializable, Delta { - - protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true; + public static class GemFireSessionAttributes extends AbstractMap { private transient final Map sessionAttributes = new HashMap<>(); - private transient final Map sessionAttributeDeltas = new HashMap<>(); private transient final Object lock; @@ -916,52 +1003,40 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi } /* (non-Javadoc) */ - public void setAttribute(String attributeName, Object attributeValue) { + protected Object getLock() { + return this.lock; + } - 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 Object setAttribute(String attributeName, Object attributeValue) { + synchronized (getLock()) { + return (attributeValue != null ? this.sessionAttributes.put(attributeName, attributeValue) + : removeAttribute(attributeName)); } } /* (non-Javadoc) */ - public void removeAttribute(String attributeName) { - - synchronized (this.lock) { - if (this.sessionAttributes.remove(attributeName) != null) { - this.sessionAttributeDeltas.put(attributeName, null); - } + public Object removeAttribute(String attributeName) { + synchronized (getLock()) { + return this.sessionAttributes.remove(attributeName); } } /* (non-Javadoc) */ @SuppressWarnings("unchecked") public T getAttribute(String attributeName) { - - synchronized (this.lock) { + synchronized (getLock()) { return (T) this.sessionAttributes.get(attributeName); } } /* (non-Javadoc) */ public Set getAttributeNames() { - - synchronized (this.lock) { + synchronized (getLock()) { return Collections.unmodifiableSet(new HashSet<>(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") @@ -982,109 +1057,39 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi }; } + /* (non-Javadoc) */ + public void clearDelta() { + } + /* (non-Javadoc) */ public void from(Session session) { - synchronized (this.lock) { + synchronized (getLock()) { session.getAttributeNames().forEach(attributeName -> setAttribute(attributeName, session.getAttribute(attributeName))); } } + /* (non-Javadoc) */ + public void from(Map map) { + + synchronized (getLock()) { + map.forEach(this::setAttribute); + } + } + /* (non-Javadoc) */ public void from(GemFireSessionAttributes sessionAttributes) { - synchronized (this.lock) { + synchronized (getLock()) { sessionAttributes.getAttributeNames().forEach(attributeName -> setAttribute(attributeName, sessionAttributes.getAttribute(attributeName))); } } - /* (non-Javadoc) */ - public void toData(DataOutput out) throws IOException { - - synchronized (this.lock) { - - Set 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 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 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 deltas = new HashMap<>(count); - - while (count-- > 0) { - deltas.put(in.readUTF(), readObject(in)); - } - - deltas.forEach((key, value) -> { - setAttribute(key, value); - this.sessionAttributeDeltas.remove(key); - }); - } - catch (ClassNotFoundException e) { - throw new InvalidDeltaException("class type in data not found", e); - } - } + return false; } @Override @@ -1092,25 +1097,4 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi 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 type, int id) { - super(type, id); - } - - @Override - public DataSerializable newInstance() { - return new GemFireSessionAttributes(); - } - } } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java index 377469b..46e4041 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfiguration.java @@ -21,6 +21,8 @@ import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newI import java.util.Optional; import java.util.concurrent.TimeUnit; +import javax.annotation.PostConstruct; + import org.apache.geode.DataSerializer; import org.apache.geode.cache.Cache; import org.apache.geode.cache.ExpirationAction; @@ -43,7 +45,6 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; @@ -408,6 +409,14 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat .orElse(DEFAULT_SESSION_SERIALIZER_BEAN_NAME); } + /** + * Determine whether the configured serialization strategy is using Apache Geode / Pivotal GemFire's + * DataSerialization framework. + * + * @return a boolean value indicating whether the configured serialization strategy is using Apache Geode + * / Pivotal GemFire's DataSerialization framework. + * @see #getSessionSerializerBeanName() + */ protected boolean isUsingDataSerialization() { return SESSION_DATA_SERIALIZER_BEAN_NAME.equals(getSessionSerializerBeanName()); } @@ -444,13 +453,20 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat setSessionSerializerBeanName( enableGemFireHttpSessionAttributes.getString("sessionSerializerBeanName")); + } + + @PostConstruct + public void init() { + + System.err.printf("SETTING SYSTEM PROPERTY (%s) TO (%s) %n", SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, + getSessionSerializerBeanName()); System.setProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, getSessionSerializerBeanName()); - getBeanFactory().registerAlias(getSessionSerializerBeanName(), SESSION_SERIALIZER_REGISTERED_ALIAS); } @Bean + @DependsOn({ SESSION_DATA_SERIALIZER_BEAN_NAME, SESSION_PDX_SERIALIZER_BEAN_NAME }) public ClientCacheConfigurer sessionClientCacheConfigurer( @Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) { @@ -458,6 +474,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat } @Bean + @DependsOn({ SESSION_DATA_SERIALIZER_BEAN_NAME, SESSION_PDX_SERIALIZER_BEAN_NAME }) public PeerCacheConfigurer sessionPeerCacheConfigurer( @Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) { @@ -618,13 +635,13 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat } @Bean(SESSION_DATA_SERIALIZER_BEAN_NAME) - @Conditional(DataSerializableSessionSerializerCondition.class) + //@Conditional(DataSerializableSessionSerializerCondition.class) public Object sessionDataSerializer() { return new PdxSerializableSessionSerializer(); } @Bean(SESSION_PDX_SERIALIZER_BEAN_NAME) - @Conditional(PdxSerializableSessionSerializerCondition.class) + //@Conditional(PdxSerializableSessionSerializerCondition.class) public Object sessionPdxSerializer() { return new DataSerializableSessionSerializer(); } @@ -683,6 +700,15 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + + System.err.printf("%1$s-System.getProperty(%2$s) = '%3$s'%n", getClass().getSimpleName(), + SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, + System.getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); + + System.err.printf("%1$s-Environment.get(%2$s) = '%3$s'%n", getClass().getSimpleName(), + SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, + context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); + return SESSION_DATA_SERIALIZER_BEAN_NAME .equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); } @@ -692,6 +718,15 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + + System.err.printf("%1$s-System.getProperty(%2$s) = '%3$s'%n", getClass().getSimpleName(), + SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, + System.getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); + + System.err.printf("%1$s-Environment.get(%2$s) = '%3$s'%n", getClass().getSimpleName(), + SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, + context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); + return SESSION_PDX_SERIALIZER_BEAN_NAME .equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)); } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/SessionSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/SessionSerializer.java index 6a106f3..42fb763 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/SessionSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/SessionSerializer.java @@ -27,28 +27,6 @@ import java.util.Optional; */ public interface SessionSerializer { - /** - * Determines whether the given {@link Object} can be de/serialized by this {@link SessionSerializer}. - * - * @param obj {@link Object} to evaluate for whether de/serialization is supported. - * @return a boolean value indicating whether the specified {@link Object} can be de/serialized - * by this {@link SessionSerializer}. - * @see #canSerialize(Class) - */ - default boolean canSerialize(Object obj) { - return Optional.ofNullable(obj).map(Object::getClass).map(this::canSerialize).orElse(false); - } - - /** - * Determines whether the given {@link Class type} can be de/serialized by this {@link SessionSerializer}. - * - * @param type {@link Class} to evaluate for whether de/serialization is supported. - * @return a boolean value indicating whether the specified {@link Class type} can be de/serialized - * by this {@link SessionSerializer}. - * @see #canSerialize(Object) - */ - boolean canSerialize(Class type); - /** * Serializes the given {@link Object} to the provided {@code out} stream. * @@ -65,4 +43,26 @@ public interface SessionSerializer { */ T deserialize(IN in); + /** + * Determines whether the given {@link Class type} can be de/serialized by this {@link SessionSerializer}. + * + * @param type {@link Class} to evaluate for whether de/serialization is supported. + * @return a boolean value indicating whether the specified {@link Class type} can be de/serialized + * by this {@link SessionSerializer}. + * @see #canSerialize(Object) + */ + boolean canSerialize(Class type); + + /** + * Determines whether the given {@link Object} can be de/serialized by this {@link SessionSerializer}. + * + * @param obj {@link Object} to evaluate for whether de/serialization is supported. + * @return a boolean value indicating whether the specified {@link Object} can be de/serialized + * by this {@link SessionSerializer}. + * @see #canSerialize(Class) + */ + default boolean canSerialize(Object obj) { + return Optional.ofNullable(obj).map(Object::getClass).map(this::canSerialize).orElse(false); + } + } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/AbstractDataSerializableSessionSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/AbstractDataSerializableSessionSerializer.java index e68ebb2..e6a88e1 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/AbstractDataSerializableSessionSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/AbstractDataSerializableSessionSerializer.java @@ -42,6 +42,8 @@ import org.springframework.session.data.gemfire.serialization.SessionSerializer; public abstract class AbstractDataSerializableSessionSerializer extends DataSerializer implements SessionSerializer { + protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true; + @Override public int getId() { return 0x0A11ACE5; @@ -52,6 +54,10 @@ public abstract class AbstractDataSerializableSessionSerializer extends DataS return new Class[0]; } + protected boolean allowJavaSerialization() { + return DEFAULT_ALLOW_JAVA_SERIALIZATION; + } + @Override @SuppressWarnings("unchecked") public boolean canSerialize(Class type) { @@ -72,11 +78,23 @@ public abstract class AbstractDataSerializableSessionSerializer extends DataS .orElse(false); } + public void serializeObject(Object obj, DataOutput out) throws IOException { + serializeObject(obj, out, allowJavaSerialization()); + } + + public void serializeObject(Object obj, DataOutput out, boolean allowJavaSerialization) throws IOException { + writeObject(obj, out, allowJavaSerialization); + } + @Override public Object fromData(DataInput in) throws IOException, ClassNotFoundException { return deserialize(in); } + public T deserializeObject(DataInput in) throws ClassNotFoundException, IOException { + return DataSerializer.readObject(in); + } + protected T safeRead(DataInput in, DataInputReader reader) { try { return reader.doRead(in); diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializer.java index 2b7fa16..f72c78a 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializer.java @@ -24,8 +24,6 @@ import java.io.DataInput; import java.io.DataOutput; import java.util.Set; -import org.apache.geode.DataSerializer; - import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer; /** @@ -64,8 +62,10 @@ public class DataSerializableSessionAttributesSerializer attributeNames.forEach(attributeName -> { safeWrite(out, output -> output.writeUTF(attributeName)); - safeWrite(out, output -> writeObject(sessionAttributes.getAttribute(attributeName), output)); + safeWrite(out, output -> serializeObject(sessionAttributes.getAttribute(attributeName), output)); }); + + sessionAttributes.clearDelta(); } } @@ -75,9 +75,11 @@ public class DataSerializableSessionAttributesSerializer GemFireSessionAttributes sessionAttributes = GemFireSessionAttributes.create(); for (int count = safeRead(in, DataInput::readInt); count > 0; count--) { - sessionAttributes.setAttribute(safeRead(in, DataInput::readUTF), safeRead(in, DataSerializer::readObject)); + sessionAttributes.setAttribute(safeRead(in, DataInput::readUTF), safeRead(in, this::deserializeObject)); } + sessionAttributes.clearDelta(); + return sessionAttributes; } } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializer.java index 67d15d2..7b7c0b3 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializer.java @@ -25,8 +25,6 @@ import java.time.Instant; import java.util.Collections; import java.util.Set; -import org.apache.geode.DataSerializer; - import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession; import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes; import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer; @@ -78,7 +76,10 @@ public class DataSerializableSessionSerializer extends AbstractDataSerializableS safeWrite(out, output -> output.writeUTF(principalName)); } - safeWrite(out, output -> writeObject(session.getAttributes(), out)); + safeWrite(out, output -> serializeObject(session.getAttributes(), out)); + + session.clearDelta(); + session.getAttributes().clearDelta(); } } @@ -119,7 +120,9 @@ public class DataSerializableSessionSerializer extends AbstractDataSerializableS session.setPrincipalName(safeRead(in, DataInput::readUTF)); } - session.getAttributes().from(this.safeRead(in, DataSerializer::readObject)); + session.getAttributes().from(this.safeRead(in, this::deserializeObject)); + session.getAttributes().clearDelta(); + session.clearDelta(); return session; } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/provider/PdxSerializableSessionSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/provider/PdxSerializableSessionSerializer.java index 4158360..6641b3f 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/provider/PdxSerializableSessionSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/provider/PdxSerializableSessionSerializer.java @@ -17,11 +17,12 @@ package org.springframework.session.data.gemfire.serialization.pdx.provider; import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession; -import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes; import java.time.Duration; import java.time.Instant; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -56,11 +57,16 @@ public class PdxSerializableSessionSerializer extends AbstractPdxSerializableSes writer.writeLong("lastAccessedTime", session.getLastAccessedTime().toEpochMilli()); writer.writeLong("maxInactiveIntervalInSeconds", session.getMaxInactiveInterval().getSeconds()); writer.writeString("principalName", session.getPrincipalName()); - writer.writeObject("attributes", session.getAttributes()); + writer.writeObject("attributes", newMap(session.getAttributes())); } } + protected Map newMap(Map map) { + return new HashMap<>(map); + } + @Override + @SuppressWarnings("unchecked") public GemFireSession deserialize(PdxReader reader) { GemFireSession session = GemFireSession.from(new AbstractSession() { @@ -92,7 +98,7 @@ public class PdxSerializableSessionSerializer extends AbstractPdxSerializableSes }); session.setPrincipalName(reader.readString("principalName")); - session.getAttributes().from((GemFireSessionAttributes) reader.readObject("attributes")); + session.getAttributes().from((Map) reader.readObject("attributes")); return session; } diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/support/ComposablePdxSerializer.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/support/ComposablePdxSerializer.java index 669651c..bf7f476 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/support/ComposablePdxSerializer.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/serialization/pdx/support/ComposablePdxSerializer.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -57,7 +58,8 @@ public class ComposablePdxSerializer implements Iterable, PdxSeri public static PdxSerializer compose(Iterable pdxSerializers) { List pdxSerializerList = - stream(nullSafeIterable(pdxSerializers).spliterator(), false).collect(Collectors.toList()); + stream(nullSafeIterable(pdxSerializers).spliterator(), false) + .filter(Objects::nonNull).collect(Collectors.toList()); return (pdxSerializerList.isEmpty() ? null : (pdxSerializerList.size() == 1 ? pdxSerializerList.get(0) diff --git a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/support/AbstractSession.java b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/support/AbstractSession.java index 5e080ec..c55ca93 100644 --- a/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/support/AbstractSession.java +++ b/spring-session-data-geode/src/main/java/org/springframework/session/data/gemfire/support/AbstractSession.java @@ -23,80 +23,84 @@ import java.util.Set; import org.springframework.session.Session; /** - * The AbstractSession class... + * The {@link AbstractSession} abstract class is a base implementation of the {@link Session} interface + * to simplify the implementation of various {@link Session} types and their capabilities. * * @author John Blum - * @since 1.0.0 + * @see org.springframework.session.data.gemfire.support.AbstractSession + * @since 2.0.0 */ public class AbstractSession implements Session { + public static final String NOT_IMPLEMENTED = "Not Implemented"; + @Override public String getId() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public void setAttribute(String attributeName, Object attributeValue) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public T getAttribute(String attributeName) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public T getAttributeOrDefault(String name, T defaultValue) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public T getRequiredAttribute(String name) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public Set getAttributeNames() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public boolean isExpired() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public Instant getCreationTime() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public void setLastAccessedTime(Instant lastAccessedTime) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public Instant getLastAccessedTime() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public void setMaxInactiveInterval(Duration interval) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public Duration getMaxInactiveInterval() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public String changeSessionId() { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } @Override public void removeAttribute(String attributeName) { - throw new UnsupportedOperationException("Not Implemented"); + throw new UnsupportedOperationException(NOT_IMPLEMENTED); } } diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTests.java similarity index 79% rename from spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java rename to spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTests.java index 5d4ac28..7109238 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTests.java @@ -33,13 +33,14 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSessionAttributes; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.DataInput; -import java.io.DataInputStream; import java.io.DataOutput; -import java.io.DataOutputStream; import java.io.IOException; import java.time.Duration; import java.time.Instant; @@ -104,7 +105,7 @@ import org.apache.commons.logging.Log; * @see edu.umd.cs.mtc.TestFramework */ @RunWith(MockitoJUnitRunner.class) -public class AbstractGemFireOperationsSessionRepositoryTest { +public class AbstractGemFireOperationsSessionRepositoryTests { protected static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600; @@ -123,20 +124,11 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Override Log newLogger() { - return AbstractGemFireOperationsSessionRepositoryTest.this.mockLog; + return mockLog; } }); } - private static Set asSet(E... elements) { - - Set set = new HashSet<>(elements.length); - - Collections.addAll(set, elements); - - return set; - } - @SuppressWarnings("unchecked") protected EntryEvent mockEntryEvent(Operation operation, K key, V oldValue, V newValue) { @@ -151,11 +143,11 @@ public class AbstractGemFireOperationsSessionRepositoryTest { } @SuppressWarnings("unchecked") - protected Region mockRegion(String name, DataPolicy dataPolicy) { + protected Region mockRegion(String name, DataPolicy dataPolicy) { Region mockRegion = mock(Region.class, name); - RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); + RegionAttributes mockRegionAttributes = mockRegionAttributes(name); given(mockRegion.getAttributes()).willReturn(mockRegionAttributes); given(mockRegionAttributes.getDataPolicy()).willReturn(dataPolicy); @@ -163,6 +155,11 @@ public class AbstractGemFireOperationsSessionRepositoryTest { return mockRegion; } + @SuppressWarnings("unchecked") + protected RegionAttributes mockRegionAttributes(String name) { + return mock(RegionAttributes.class, name); + } + protected Session mockSession(String sessionId, long creationAndLastAccessedTime, long maxInactiveIntervalInSeconds) { @@ -387,7 +384,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isEqualTo(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -430,7 +427,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -553,7 +550,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isEqualTo(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -593,7 +590,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -632,7 +629,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -674,7 +671,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isEqualTo(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -713,7 +710,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -752,7 +749,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -802,7 +799,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isEqualTo(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -874,7 +871,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isEqualTo(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -906,7 +903,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; - assertThat(sessionEvent.getSource()).isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository); + assertThat(sessionEvent.getSource()).isEqualTo(AbstractGemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId); @@ -956,8 +953,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Instant beforeOrAtCreationTime = Instant.now(); - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession(); + GemFireSession session = new GemFireSession(); assertThat(session.getId()).isNotNull(); assertThat(session.getCreationTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); @@ -972,8 +968,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Instant beforeOrAtCreationTime = Instant.now(); - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1"); + GemFireSession session = new GemFireSession("1"); assertThat(session.getId()).isEqualTo("1"); assertThat(session.getCreationTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); @@ -986,7 +981,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test(expected = IllegalArgumentException.class) public void constructGemFireSessionWithUnspecifiedId() { try { - new AbstractGemFireOperationsSessionRepository.GemFireSession(" "); + new GemFireSession(" "); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessage("ID is required"); @@ -1013,8 +1008,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { given(mockSession.getAttribute(eq("attrOne"))).willReturn("testOne"); given(mockSession.getAttribute(eq("attrTwo"))).willReturn("testTwo"); - AbstractGemFireOperationsSessionRepository.GemFireSession gemfireSession = - new AbstractGemFireOperationsSessionRepository.GemFireSession(mockSession); + GemFireSession gemfireSession = new GemFireSession(mockSession); assertThat(gemfireSession.getId()).isEqualTo("2"); assertThat(gemfireSession.getCreationTime()).isEqualTo(expectedCreationTime); @@ -1036,7 +1030,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test(expected = IllegalArgumentException.class) public void constructGemFireSessionWithNullSession() { try { - new AbstractGemFireOperationsSessionRepository.GemFireSession((Session) null); + new GemFireSession((Session) null); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessage("The Session to copy cannot be null"); @@ -1053,8 +1047,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Duration maxInactiveInterval = Duration.ofSeconds(120L); - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(maxInactiveInterval); + GemFireSession session = GemFireSession.create(maxInactiveInterval); assertThat(session).isNotNull(); assertThat(session.getId()).isNotNull(); @@ -1062,7 +1055,23 @@ public class AbstractGemFireOperationsSessionRepositoryTest { assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime()); assertThat(session.getMaxInactiveInterval()).isEqualTo(maxInactiveInterval); assertThat(session.getAttributeNames()).isNotNull(); - assertThat(session.getAttributeNames().isEmpty()).isTrue(); + assertThat(session.getAttributeNames()).isEmpty(); + } + + @Test + public void createNewGemFireSessionWithDefaultMaxInactiveInterval() { + + Instant beforeOrAtCreationTime = Instant.now(); + + GemFireSession session = GemFireSession.create(); + + assertThat(session).isNotNull(); + assertThat(session.getId()).isNotNull(); + assertThat(session.getCreationTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); + assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime()); + assertThat(session.getMaxInactiveInterval()).isEqualTo(GemFireSession.DEFAULT_MAX_INACTIVE_INTERVAL); + assertThat(session.getAttributeNames()).isNotNull(); + assertThat(session.getAttributeNames()).isEmpty(); } @Test @@ -1078,8 +1087,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { given(mockSession.getAttributeNames()).willReturn(Collections.emptySet()); - AbstractGemFireOperationsSessionRepository.GemFireSession gemfireSession = - AbstractGemFireOperationsSessionRepository.GemFireSession.from(mockSession); + GemFireSession gemfireSession = GemFireSession.from(mockSession); assertThat(gemfireSession).isNotNull(); assertThat(gemfireSession.getId()).isEqualTo("4"); @@ -1100,11 +1108,9 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void fromExistingGemFireSessionIsGemFireSession() { - AbstractGemFireOperationsSessionRepository.GemFireSession gemfireSession = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(Duration.ofSeconds(300)); + GemFireSession gemfireSession = GemFireSession.create(); - AbstractGemFireOperationsSessionRepository.GemFireSession fromGemFireSession = - AbstractGemFireOperationsSessionRepository.GemFireSession.from(gemfireSession); + GemFireSession fromGemFireSession = GemFireSession.from(gemfireSession); assertThat(fromGemFireSession).isSameAs(gemfireSession); } @@ -1112,12 +1118,10 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void setGetAndRemoveAttribute() { - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(Duration.ofSeconds(60)); + GemFireSession session = GemFireSession.create(); assertThat(session).isNotNull(); - assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(60)); - assertThat(session.getAttributeNames().isEmpty()).isTrue(); + assertThat(session.getAttributeNames()).isEmpty(); session.setAttribute("attrOne", "testOne"); @@ -1149,8 +1153,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Duration expectedMaxInactiveIntervalInSeconds = Duration.ofSeconds(-1); - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(expectedMaxInactiveIntervalInSeconds); + GemFireSession session = GemFireSession.create(expectedMaxInactiveIntervalInSeconds); assertThat(session).isNotNull(); assertThat(session.getMaxInactiveInterval()).isEqualTo(expectedMaxInactiveIntervalInSeconds); @@ -1162,8 +1165,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Duration expectedMaxInactiveIntervalInSeconds = Duration.ZERO; - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(expectedMaxInactiveIntervalInSeconds); + GemFireSession session = GemFireSession.create(expectedMaxInactiveIntervalInSeconds); assertThat(session).isNotNull(); assertThat(session.getMaxInactiveInterval()).isEqualTo(expectedMaxInactiveIntervalInSeconds); @@ -1175,12 +1177,11 @@ public class AbstractGemFireOperationsSessionRepositoryTest { long expectedMaxInactiveIntervalInSeconds = TimeUnit.HOURS.toSeconds(2); - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create( - Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); + GemFireSession session = GemFireSession.create(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); assertThat(session).isNotNull(); - assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); + assertThat(session.getMaxInactiveInterval()) + .isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); Instant now = Instant.now(); @@ -1195,12 +1196,11 @@ public class AbstractGemFireOperationsSessionRepositoryTest { int expectedMaxInactiveIntervalInSeconds = 60; - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create( - Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); + GemFireSession session = GemFireSession.create(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); assertThat(session).isNotNull(); - assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); + assertThat(session.getMaxInactiveInterval()) + .isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); Instant twoHoursAgo = Instant.ofEpochMilli(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2)); @@ -1213,8 +1213,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void setAndGetPrincipalName() { - AbstractGemFireOperationsSessionRepository.GemFireSession session = - AbstractGemFireOperationsSessionRepository.GemFireSession.create(Duration.ZERO); + GemFireSession session = GemFireSession.create(Duration.ZERO); assertThat(session).isNotNull(); assertThat(session.getPrincipalName()).isNull(); @@ -1236,141 +1235,6 @@ public class AbstractGemFireOperationsSessionRepositoryTest { assertThat(session.getPrincipalName()).isNull(); } - @Test - public void sessionToData() throws Exception { - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1") { - - @Override - void writeObject(Object obj, DataOutput out) throws IOException { - assertThat(obj).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes.class); - assertThat(out).isNotNull(); - } - }; - - session.setLastAccessedTime(Instant.ofEpochMilli(123L)); - session.setMaxInactiveInterval(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS)); - session.setPrincipalName("jblum"); - - DataOutput mockDataOutput = mock(DataOutput.class); - - session.toData(mockDataOutput); - - verify(mockDataOutput, times(1)).writeUTF(eq("1")); - verify(mockDataOutput, times(1)).writeLong(eq(session.getCreationTime().toEpochMilli())); - verify(mockDataOutput, times(1)).writeLong(eq(session.getLastAccessedTime().toEpochMilli())); - verify(mockDataOutput, times(1)).writeLong(eq(session.getMaxInactiveInterval().getSeconds())); - verify(mockDataOutput, times(1)).writeInt(eq("jblum".length())); - verify(mockDataOutput, times(1)).writeUTF(eq(session.getPrincipalName())); - } - - @Test - public void sessionFromData() throws Exception { - - long expectedCreationTime = 1L; - long expectedLastAccessedTime = 2L; - long expectedMaxInactiveIntervalInSeconds = TimeUnit.HOURS.toSeconds(6); - - String expectedPrincipalName = "jblum"; - String expectedSessionId = "2"; - - DataInput mockDataInput = mock(DataInput.class); - - given(mockDataInput.readUTF()).willReturn(expectedSessionId).willReturn(expectedPrincipalName); - given(mockDataInput.readLong()).willReturn(expectedCreationTime).willReturn(expectedLastAccessedTime) - .willReturn(expectedMaxInactiveIntervalInSeconds); - given(mockDataInput.readInt()).willReturn(expectedPrincipalName.length()); - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1") { - - @Override - @SuppressWarnings("unchecked") - T readObject(DataInput in) throws ClassNotFoundException, IOException { - - assertThat(in).isNotNull(); - - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); - - sessionAttributes.setAttribute("attrOne", "testOne"); - sessionAttributes.setAttribute("attrTwo", "testTwo"); - - return (T) sessionAttributes; - } - }; - - session.fromData(mockDataInput); - - Set expectedAttributeNames = - asSet("attrOne", "attrTwo", FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - - assertThat(session.getId()).isEqualTo(expectedSessionId); - assertThat(session.getCreationTime()).isEqualTo(Instant.ofEpochMilli(expectedCreationTime)); - assertThat(session.getLastAccessedTime()).isEqualTo(Instant.ofEpochMilli(expectedLastAccessedTime)); - assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); - assertThat(session.getPrincipalName()).isEqualTo(expectedPrincipalName); - assertThat(session.getAttributeNames()).hasSize(3); - assertThat(session.getAttributeNames()).containsAll(expectedAttributeNames); - assertThat(session.getAttribute("attrOne")).isEqualTo("testOne"); - assertThat(session.getAttribute("attrTwo")).isEqualTo("testTwo"); - assertThat(session.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME)) - .isEqualTo(expectedPrincipalName); - - verify(mockDataInput, times(2)).readUTF(); - verify(mockDataInput, times(3)).readLong(); - verify(mockDataInput, times(1)).readInt(); - } - - @Test - public void sessionToDataThenFromDataWhenPrincipalNameIsNullGetsHandledProperly() - throws ClassNotFoundException, IOException { - - Instant beforeOrAtCreationTime = Instant.now(); - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession expectedSession = - new AbstractGemFireOperationsSessionRepository.GemFireSession("123") { - - @Override - void writeObject(Object obj, DataOutput out) throws IOException { - assertThat(obj).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes.class); - assertThat(out).isNotNull(); - } - }; - - assertThat(expectedSession.getId()).isEqualTo("123"); - assertThat(expectedSession.getCreationTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); - assertThat(expectedSession.getLastAccessedTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); - assertThat(expectedSession.getMaxInactiveInterval()).isEqualTo(Duration.ZERO); - assertThat(expectedSession.getPrincipalName()).isNull(); - - ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); - - expectedSession.toData(new DataOutputStream(outBytes)); - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession deserializedSession = - new AbstractGemFireOperationsSessionRepository.GemFireSession("0") { - @Override - @SuppressWarnings("unchecked") - T readObject(DataInput in) throws ClassNotFoundException, IOException { - return (T) new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); - } - }; - - deserializedSession.fromData(new DataInputStream(new ByteArrayInputStream(outBytes.toByteArray()))); - - assertThat(deserializedSession).isEqualTo(expectedSession); - assertThat(deserializedSession.getCreationTime()).isEqualTo(expectedSession.getCreationTime()); - assertThat(deserializedSession.getLastAccessedTime()).isEqualTo(expectedSession.getLastAccessedTime()); - assertThat(deserializedSession.getMaxInactiveInterval()).isEqualTo(expectedSession.getMaxInactiveInterval()); - assertThat(deserializedSession.getPrincipalName()).isNull(); - } - @Test public void hasDeltaWhenNoSessionChangesIsFalse() { assertThat(new AbstractGemFireOperationsSessionRepository.GemFireSession().hasDelta()).isFalse(); @@ -1379,8 +1243,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void hasDeltaWhenSessionAttributesChangeIsTrue() { - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession(); + GemFireSession session = new DeltaCapableGemFireSession(); assertThat(session.hasDelta()).isFalse(); @@ -1439,15 +1302,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { DataOutput mockDataOutput = mock(DataOutput.class); @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession() { - - @Override - void writeObject(Object obj, DataOutput out) throws IOException { - assertThat(String.valueOf(obj)).isEqualTo("test"); - assertThat(out).isSameAs(mockDataOutput); - } - }; + DeltaCapableGemFireSession session = new DeltaCapableGemFireSession(); session.setLastAccessedTime(Instant.ofEpochMilli(1L)); session.setMaxInactiveInterval(Duration.ofSeconds(300L)); @@ -1470,31 +1325,24 @@ public class AbstractGemFireOperationsSessionRepositoryTest { DataInput mockDataInput = mock(DataInput.class); + given(mockDataInput.readUTF()).willReturn("1"); given(mockDataInput.readLong()).willReturn(1L).willReturn(600L); given(mockDataInput.readInt()).willReturn(0); @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession() { - - @Override - @SuppressWarnings("unchecked") - T readObject(DataInput in) throws ClassNotFoundException, IOException { - assertThat(in).isSameAs(mockDataInput); - return (T) "test"; - } - }; + DeltaCapableGemFireSession session = new DeltaCapableGemFireSession(); session.fromDelta(mockDataInput); assertThat(session.hasDelta()).isFalse(); + assertThat(session.getId()).isEqualTo("1"); assertThat(session.getLastAccessedTime()).isEqualTo(Instant.ofEpochMilli(1L)); assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(600L)); assertThat(session.getAttributeNames().isEmpty()).isTrue(); + verify(mockDataInput, times(1)).readUTF(); verify(mockDataInput, times(2)).readLong(); verify(mockDataInput, times(1)).readInt(); - verify(mockDataInput, never()).readUTF(); } @Test @@ -1502,12 +1350,10 @@ public class AbstractGemFireOperationsSessionRepositoryTest { Instant twoHoursAgo = Instant.now().minusMillis(TimeUnit.HOURS.toMillis(2)); - AbstractGemFireOperationsSessionRepository.GemFireSession sessionOne = - new AbstractGemFireOperationsSessionRepository.GemFireSession( - mockSession("1", twoHoursAgo.toEpochMilli(), MAX_INACTIVE_INTERVAL_IN_SECONDS)); + GemFireSession sessionOne = + new GemFireSession<>(mockSession("1", twoHoursAgo.toEpochMilli(), MAX_INACTIVE_INTERVAL_IN_SECONDS)); - AbstractGemFireOperationsSessionRepository.GemFireSession sessionTwo = - new AbstractGemFireOperationsSessionRepository.GemFireSession("2"); + GemFireSession sessionTwo = new GemFireSession<>("2"); assertThat(sessionOne.getCreationTime()).isEqualTo(twoHoursAgo); assertThat(sessionTwo.getCreationTime().isAfter(twoHoursAgo)).isTrue(); @@ -1519,15 +1365,13 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void sessionEqualsDifferentSessionBasedOnId() { - AbstractGemFireOperationsSessionRepository.GemFireSession sessionOne = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1"); + GemFireSession sessionOne = new GemFireSession("1"); sessionOne.setLastAccessedTime(Instant.ofEpochSecond(12345L)); sessionOne.setMaxInactiveInterval(Duration.ofSeconds(120L)); sessionOne.setPrincipalName("jblum"); - AbstractGemFireOperationsSessionRepository.GemFireSession sessionTwo = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1"); + GemFireSession sessionTwo = new GemFireSession("1"); sessionTwo.setLastAccessedTime(Instant.ofEpochSecond(67890L)); sessionTwo.setMaxInactiveInterval(Duration.ofSeconds(300L)); @@ -1543,8 +1387,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void sessionHashCodeIsNotEqualToStringIdHashCode() { - AbstractGemFireOperationsSessionRepository.GemFireSession session = - new AbstractGemFireOperationsSessionRepository.GemFireSession("1"); + GemFireSession session = new GemFireSession("1"); assertThat(session.getId()).isEqualTo("1"); assertThat(session.hashCode()).isNotEqualTo("1".hashCode()); @@ -1559,8 +1402,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { given(mockSession.getAttribute(eq("attrOne"))).willReturn("testOne"); given(mockSession.getAttribute(eq("attrTwo"))).willReturn("testTwo"); - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); + GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(); assertThat(sessionAttributes.getAttributeNames().isEmpty()).isTrue(); @@ -1585,8 +1427,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { source.setAttribute("attrOne", "testOne"); source.setAttribute("attrTwo", "testTwo"); - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes target = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); + GemFireSessionAttributes target = new GemFireSessionAttributes(); assertThat(target.getAttributeNames().isEmpty()).isTrue(); @@ -1598,69 +1439,6 @@ public class AbstractGemFireOperationsSessionRepositoryTest { assertThat(target.getAttribute("attrTwo")).isEqualTo("testTwo"); } - @Test - public void sessionAttributesToData() throws Exception { - - DataOutput mockDataOutput = mock(DataOutput.class); - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes() { - - private int count = 0; - - @Override - void writeObject(Object obj, DataOutput out) throws IOException { - assertThat(Arrays.asList("testOne", "testTwo").get(count++)).isEqualTo(String.valueOf(obj)); - assertThat(out).isSameAs(mockDataOutput); - } - }; - - sessionAttributes.setAttribute("attrOne", "testOne"); - sessionAttributes.setAttribute("attrTwo", "testTwo"); - - sessionAttributes.toData(mockDataOutput); - - verify(mockDataOutput, times(1)).writeInt(eq(2)); - verify(mockDataOutput, times(1)).writeUTF(eq("attrOne")); - verify(mockDataOutput, times(1)).writeUTF(eq("attrTwo")); - } - - @Test - public void sessionAttributesFromData() throws Exception { - - DataInput mockDataInput = mock(DataInput.class); - - given(mockDataInput.readInt()).willReturn(2); - given(mockDataInput.readUTF()).willReturn("attrOne").willReturn("attrTwo"); - - @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes() { - - private int count = 0; - - @Override - @SuppressWarnings("unchecked") - T readObject(DataInput in) throws ClassNotFoundException, IOException { - assertThat(in).isSameAs(mockDataInput); - return (T) Arrays.asList("testOne", "testTwo").get(count++); - } - }; - - assertThat(sessionAttributes.getAttributeNames().isEmpty()).isTrue(); - - sessionAttributes.fromData(mockDataInput); - - assertThat(sessionAttributes.getAttributeNames().size()).isEqualTo(2); - assertThat(sessionAttributes.getAttributeNames().containsAll(asSet("attrOne", "attrTwo"))).isTrue(); - assertThat(sessionAttributes.getAttribute("attrOne")).isEqualTo("testOne"); - assertThat(sessionAttributes.getAttribute("attrTwo")).isEqualTo("testTwo"); - - verify(mockDataInput, times(1)).readInt(); - verify(mockDataInput, times(2)).readUTF(); - } - @Test public void sessionAttributesHasDeltaIsFalse() { assertThat(new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes().hasDelta()).isFalse(); @@ -1669,8 +1447,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void sessionAttributesHasDeltaIsTrue() { - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); + GemFireSessionAttributes sessionAttributes = new DeltaCapableGemFireSessionAttributes(); assertThat(sessionAttributes.hasDelta()).isFalse(); @@ -1686,13 +1463,12 @@ public class AbstractGemFireOperationsSessionRepositoryTest { DataOutput mockDataOutput = mock(DataOutput.class); @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes() { + DeltaCapableGemFireSessionAttributes sessionAttributes = new DeltaCapableGemFireSessionAttributes() { private int count = 0; @Override - void writeObject(Object obj, DataOutput out) throws IOException { + protected void writeObject(Object obj, DataOutput out) throws IOException { assertThat(Arrays.asList("testOne", "testTwo", "testThree").get(count++)).isEqualTo(String.valueOf(obj)); assertThat(out).isSameAs(mockDataOutput); } @@ -1741,14 +1517,13 @@ public class AbstractGemFireOperationsSessionRepositoryTest { given(mockDataInput.readUTF()).willReturn("attrOne").willReturn("attrTwo"); @SuppressWarnings("serial") - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes() { + DeltaCapableGemFireSessionAttributes sessionAttributes = new DeltaCapableGemFireSessionAttributes() { private int count = 0; @Override @SuppressWarnings("unchecked") - T readObject(DataInput in) throws ClassNotFoundException, IOException { + protected T readObject(DataInput in) throws ClassNotFoundException, IOException { assertThat(in).isSameAs(mockDataInput); return (T) Arrays.asList("testOne", "testTwo", "testThree").get(count++); } @@ -1802,8 +1577,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Test public void sessionAttributesEntrySetIteratesAttributeNameValues() { - AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes sessionAttributes = - new AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes(); + GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(); sessionAttributes.setAttribute("keyOne", "valueOne"); sessionAttributes.setAttribute("keyTwo", "valueTwo"); @@ -1813,8 +1587,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest { assertThat(sessionAttributeEntries).isNotNull(); assertThat(sessionAttributeEntries.size()).isEqualTo(2); - Set expectedNames = asSet("keyOne", "keyTwo"); - Set expectedValues = asSet("valueOne", "valueTwo"); + Set expectedNames = new HashSet<>(asSet("keyOne", "keyTwo")); + Set expectedValues = new HashSet<>(asSet("valueOne", "valueTwo")); for (Map.Entry entry : sessionAttributeEntries) { expectedNames.remove(entry.getKey()); @@ -1828,8 +1602,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest { assertThat(sessionAttributeEntries.size()).isEqualTo(3); - expectedNames = asSet("keyOne", "keyTwo"); - expectedValues = asSet("valueOne", "valueTwo"); + expectedNames = new HashSet<>(asSet("keyOne", "keyTwo")); + expectedValues = new HashSet<>(asSet("valueOne", "valueTwo")); for (Map.Entry entry : sessionAttributeEntries) { expectedNames.remove(entry.getKey()); @@ -1858,7 +1632,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @SuppressWarnings("unused") protected static final class ThreadSafeSessionTest extends MultithreadedTestCase { - private AbstractGemFireOperationsSessionRepository.GemFireSession session; + private GemFireSession session; private final Instant beforeOrAtCreationTime = Instant.now(); @@ -1867,7 +1641,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest { @Override public void initialize() { - this.session = new AbstractGemFireOperationsSessionRepository.GemFireSession("1"); + this.session = new GemFireSession<>("1"); assertThat(this.session).isNotNull(); assertThat(this.session.getId()).isEqualTo("1"); diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTests.java similarity index 98% rename from spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java rename to spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTests.java index fa26511..b35f63d 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTests.java @@ -74,7 +74,7 @@ import org.springframework.session.events.SessionDeletedEvent; * @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository */ @RunWith(MockitoJUnitRunner.class) -public class GemFireOperationsSessionRepositoryTest { +public class GemFireOperationsSessionRepositoryTests { protected static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600; @@ -271,7 +271,7 @@ public class GemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; assertThat(sessionEvent.getSource()) - .isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository); + .isSameAs(GemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isSameAs(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId); @@ -393,7 +393,7 @@ public class GemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; - assertThat(sessionEvent.getSource()).isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository); + assertThat(sessionEvent.getSource()).isSameAs(GemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isSameAs(mockSession); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId); @@ -423,7 +423,7 @@ public class GemFireOperationsSessionRepositoryTest { AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent; - assertThat(sessionEvent.getSource()).isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository); + assertThat(sessionEvent.getSource()).isSameAs(GemFireOperationsSessionRepositoryTests.this.sessionRepository); assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId); diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTest.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java similarity index 78% rename from spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTest.java rename to spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java index 23dd3c4..17c7376 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTest.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionConfigurationTests.java @@ -28,6 +28,7 @@ import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; +import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; @@ -41,6 +42,8 @@ import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientRegionShortcut; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.GemfireOperations; import org.springframework.data.gemfire.GemfireTemplate; @@ -50,26 +53,36 @@ import org.springframework.session.data.gemfire.GemFireOperationsSessionReposito import org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean; /** - * The GemFireHttpSessionConfigurationTest class is a test suite of test cases testing the - * contract and functionality of the {@link GemFireHttpSessionConfiguration} class. + * Unit tests for {@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.ExpirationAttributes + * @see org.apache.geode.cache.RegionAttributes * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.core.type.AnnotationMetadata + * @see org.springframework.data.gemfire.GemfireOperations + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.session.Session + * @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository + * @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration */ -public class GemFireHttpSessionConfigurationTest { +public class GemFireHttpSessionConfigurationTests { private GemFireHttpSessionConfiguration gemfireConfiguration; + @AfterClass + public static void tearDown() { + System.clearProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME); + } + @SuppressWarnings("unchecked") protected T getField(Object obj, String fieldName) { try { @@ -197,7 +210,7 @@ public class GemFireHttpSessionConfigurationTest { } @Test - public void setAndGetSpringSessionGemFireRegionName() { + public void setAndGetSessionRegionName() { assertThat(this.gemfireConfiguration.getSessionRegionName()).isEqualTo( GemFireHttpSessionConfiguration.DEFAULT_SESSION_REGION_NAME); @@ -222,6 +235,61 @@ public class GemFireHttpSessionConfigurationTest { GemFireHttpSessionConfiguration.DEFAULT_SESSION_REGION_NAME); } + @Test + public void setAndGetSessionSerializerBeanName() { + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.DEFAULT_SESSION_SERIALIZER_BEAN_NAME); + + this.gemfireConfiguration.setSessionSerializerBeanName( + GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME); + + this.gemfireConfiguration.setSessionSerializerBeanName(null); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.DEFAULT_SESSION_SERIALIZER_BEAN_NAME); + + this.gemfireConfiguration.setSessionSerializerBeanName( + GemFireHttpSessionConfiguration.SESSION_PDX_SERIALIZER_BEAN_NAME); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.SESSION_PDX_SERIALIZER_BEAN_NAME); + } + + @Test + public void isUsingDataSerializationIsFalse() { + + this.gemfireConfiguration.setSessionSerializerBeanName("test"); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()).isEqualTo("test"); + assertThat(this.gemfireConfiguration.isUsingDataSerialization()).isFalse(); + + this.gemfireConfiguration.setSessionSerializerBeanName( + GemFireHttpSessionConfiguration.SESSION_PDX_SERIALIZER_BEAN_NAME); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.SESSION_PDX_SERIALIZER_BEAN_NAME); + + assertThat(this.gemfireConfiguration.isUsingDataSerialization()).isFalse(); + } + + @Test + public void isUsingDataSerializationIsTrue() { + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME); + assertThat(this.gemfireConfiguration.isUsingDataSerialization()).isTrue(); + + this.gemfireConfiguration.setSessionSerializerBeanName(null); + + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()) + .isEqualTo(GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME); + assertThat(this.gemfireConfiguration.isUsingDataSerialization()).isTrue(); + } + @Test public void setsImportMetadata() { @@ -235,6 +303,7 @@ public class GemFireHttpSessionConfigurationTest { annotationAttributes.put("poolName", "TestPool"); annotationAttributes.put("serverRegionShortcut", RegionShortcut.REPLICATE); annotationAttributes.put("regionName", "TEST"); + annotationAttributes.put("sessionSerializerBeanName", "testSessionSerializer"); given(mockAnnotationMetadata.getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName()))) .willReturn(annotationAttributes); @@ -247,8 +316,36 @@ public class GemFireHttpSessionConfigurationTest { assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo("TestPool"); assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE); assertThat(this.gemfireConfiguration.getSessionRegionName()).isEqualTo("TEST"); + assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()).isEqualTo("testSessionSerializer"); - verify(mockAnnotationMetadata, times(1)).getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName())); + verify(mockAnnotationMetadata, times(1)) + .getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName())); + + } + + @Test + public void postConstructInitSetsSystemPropertyAndRegistersBeanAlias() { + + ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class); + + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class); + + given(mockApplicationContext.getBeanFactory()).willReturn(mockBeanFactory); + + assertThat(System.getProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_REGISTERED_ALIAS)).isNull(); + + this.gemfireConfiguration.setApplicationContext(mockApplicationContext); + this.gemfireConfiguration.setSessionSerializerBeanName("testSessionSerializer"); + this.gemfireConfiguration.init(); + + assertThat(this.gemfireConfiguration.getApplicationContext()).isSameAs(mockApplicationContext); + assertThat(System.getProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME)) + .isEqualTo("testSessionSerializer"); + + verify(mockApplicationContext, times(1)).getBeanFactory(); + + verify(mockBeanFactory, times(1)).registerAlias(eq("testSessionSerializer"), + eq(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_REGISTERED_ALIAS)); } @Test diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTest.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTests.java similarity index 97% rename from spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTest.java rename to spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTests.java index 02bd463..a3db163 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTest.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/config/annotation/web/http/support/GemFireCacheTypeAwareRegionFactoryBeanTests.java @@ -39,7 +39,7 @@ import org.springframework.data.gemfire.client.Interest; import org.springframework.session.Session; /** - * The GemFireCacheTypeAwareRegionFactoryBeanTest class is a test suite of test cases + * The GemFireCacheTypeAwareRegionFactoryBeanTests class is a test suite of test cases * testing the contract and functionality of the GemFireCacheTypeAwareRegionFactoryBean * class. * @@ -60,7 +60,7 @@ import org.springframework.session.Session; * @see org.apache.geode.cache.client.ClientRegionShortcut */ @RunWith(MockitoJUnitRunner.class) -public class GemFireCacheTypeAwareRegionFactoryBeanTest { +public class GemFireCacheTypeAwareRegionFactoryBeanTests { @Mock Cache mockCache; @@ -89,13 +89,13 @@ public class GemFireCacheTypeAwareRegionFactoryBeanTest { @Override protected Region newClientRegion(GemFireCache gemfireCache) throws Exception { assertThat(gemfireCache).isSameAs(expectedCache); - return GemFireCacheTypeAwareRegionFactoryBeanTest.this.mockClientRegion; + return GemFireCacheTypeAwareRegionFactoryBeanTests.this.mockClientRegion; } @Override protected Region newServerRegion(GemFireCache gemfireCache) throws Exception { assertThat(gemfireCache).isSameAs(expectedCache); - return GemFireCacheTypeAwareRegionFactoryBeanTest.this.mockServerRegion; + return GemFireCacheTypeAwareRegionFactoryBeanTests.this.mockServerRegion; } }; diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializerTests.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializerTests.java new file mode 100644 index 0000000..3a9f824 --- /dev/null +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionAttributesSerializerTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 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.serialization.data.provider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes; + +import java.io.DataInput; +import java.io.DataOutput; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +/** + * Unit tests for {@link DataSerializableSessionAttributesSerializer}. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.Spy + * @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes + * @see org.springframework.session.data.gemfire.serialization.data.provider.DataSerializableSessionAttributesSerializer + * @since 2.0.0 + */ +public class DataSerializableSessionAttributesSerializerTests { + + private DataSerializableSessionAttributesSerializer sessionAttributesSerializer = + spy(new DataSerializableSessionAttributesSerializer()); + + @Test + public void getIdReturnsSameValue() { + + int id = this.sessionAttributesSerializer.getId(); + + assertThat(id).isNotEqualTo(0); + assertThat(id).isEqualTo(this.sessionAttributesSerializer.getId()); + } + + @Test + public void supportedClassesContainsGemFireSessionAttributes() { + assertThat(this.sessionAttributesSerializer.getSupportedClasses()).contains(GemFireSessionAttributes.class); + } + + @Test + public void sessionAttributesToData() throws Exception { + + DataOutput mockDataOutput = mock(DataOutput.class); + + GemFireSessionAttributes sessionAttributes = GemFireSessionAttributes.create(); + + sessionAttributes.setAttribute("attrOne", "testOne"); + sessionAttributes.setAttribute("attrTwo", "testTwo"); + + doAnswer(invocation -> { + + DataOutput dataOutput = invocation.getArgument(1); + + dataOutput.writeUTF(invocation.getArgument(0)); + + return null; + + }).when(sessionAttributesSerializer).serializeObject(any(), any(DataOutput.class)); + + sessionAttributesSerializer.serialize(sessionAttributes, mockDataOutput); + + verify(mockDataOutput, times(1)).writeInt(eq(2)); + verify(mockDataOutput, times(1)).writeUTF(eq("attrOne")); + verify(mockDataOutput, times(1)).writeUTF(eq("testOne")); + verify(mockDataOutput, times(1)).writeUTF(eq("attrTwo")); + verify(mockDataOutput, times(1)).writeUTF(eq("testTwo")); + } + + @Test + public void sessionAttributesFromData() throws Exception { + + AtomicInteger count = new AtomicInteger(0); + + DataInput mockDataInput = mock(DataInput.class); + + given(mockDataInput.readInt()).willReturn(2); + given(mockDataInput.readUTF()).willReturn("attrOne").willReturn("attrTwo"); + + doAnswer(invocation -> Arrays.asList("testOne", "testTwo").get(count.getAndIncrement())) + .when(sessionAttributesSerializer).deserializeObject(any(DataInput.class)); + + GemFireSessionAttributes sessionAttributes = sessionAttributesSerializer.deserialize(mockDataInput); + + assertThat(sessionAttributes).isNotNull(); + assertThat(sessionAttributes.getAttributeNames()).hasSize(2); + assertThat(sessionAttributes.getAttributeNames()).containsAll(asSet("attrOne", "attrTwo")); + assertThat(sessionAttributes.getAttribute("attrOne")).isEqualTo("testOne"); + assertThat(sessionAttributes.getAttribute("attrTwo")).isEqualTo("testTwo"); + + verify(mockDataInput, times(1)).readInt(); + verify(mockDataInput, times(2)).readUTF(); + } +} diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializerTests.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializerTests.java new file mode 100644 index 0000000..fe03cd3 --- /dev/null +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/serialization/data/provider/DataSerializableSessionSerializerTests.java @@ -0,0 +1,201 @@ +/* + * Copyright 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.serialization.data.provider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession; +import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import org.springframework.session.FindByIndexNameSessionRepository; + +/** + * Unit tests for {@link DataSerializableSessionSerializer}. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.Spy + * @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession + * @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes + * @see org.springframework.session.data.gemfire.serialization.data.provider.DataSerializableSessionSerializer + * @since 2.0.0 + */ +public class DataSerializableSessionSerializerTests { + + private DataSerializableSessionSerializer sessionSerializer = spy(new DataSerializableSessionSerializer()); + + @Test + public void getIdReturnsSameValue() { + + int id = this.sessionSerializer.getId(); + + assertThat(id).isNotEqualTo(0); + assertThat(id).isEqualTo((this.sessionSerializer.getId())); + } + + @Test + public void supportedClassContainsGemFireSession() { + assertThat(this.sessionSerializer.getSupportedClasses()).contains(GemFireSession.class); + } + + @Test + public void sessionToData() throws Exception { + + GemFireSession session = GemFireSession.create(); + + session.setLastAccessedTime(Instant.ofEpochMilli(123L)); + session.setMaxInactiveInterval(Duration.ofSeconds(60L)); + session.setPrincipalName("jblum"); + + DataOutput mockDataOutput = mock(DataOutput.class); + + doAnswer(invocation -> { + assertThat(invocation.getArgument(0)).isEqualTo(session.getAttributes()); + assertThat(invocation.getArgument(1)).isEqualTo(mockDataOutput); + return null; + }).when(this.sessionSerializer).serializeObject(any(), any(DataOutput.class)); + + assertThat(session.hasDelta()).isTrue(); + + this.sessionSerializer.serialize(session, mockDataOutput); + + assertThat(session.hasDelta()).isFalse(); + + verify(mockDataOutput, times(1)).writeUTF(eq(session.getId())); + verify(mockDataOutput, times(1)).writeLong(eq(session.getCreationTime().toEpochMilli())); + verify(mockDataOutput, times(1)).writeLong(eq(session.getLastAccessedTime().toEpochMilli())); + verify(mockDataOutput, times(1)).writeLong(eq(session.getMaxInactiveInterval().getSeconds())); + verify(mockDataOutput, times(1)).writeInt(eq("jblum".length())); + verify(mockDataOutput, times(1)).writeUTF(eq(session.getPrincipalName())); + verify(this.sessionSerializer, times(1)) + .serializeObject(eq(session.getAttributes()), eq(mockDataOutput)); + } + + @Test + public void sessionFromData() throws Exception { + + long expectedCreationTime = 1L; + long expectedLastAccessedTime = 2L; + long expectedMaxInactiveIntervalInSeconds = TimeUnit.HOURS.toSeconds(2); + + String expectedPrincipalName = "jblum"; + String expectedSessionId = "2"; + + DataInput mockDataInput = mock(DataInput.class); + + given(mockDataInput.readUTF()).willReturn(expectedSessionId).willReturn(expectedPrincipalName); + given(mockDataInput.readLong()).willReturn(expectedCreationTime).willReturn(expectedLastAccessedTime) + .willReturn(expectedMaxInactiveIntervalInSeconds); + given(mockDataInput.readInt()).willReturn(expectedPrincipalName.length()); + + doAnswer(invocation -> { + + GemFireSessionAttributes sessionAttributes = GemFireSessionAttributes.create(); + + sessionAttributes.setAttribute("attrOne", "testOne"); + sessionAttributes.setAttribute("attrTwo", "testTwo"); + + return sessionAttributes; + + }).when(this.sessionSerializer).deserializeObject(any(DataInput.class)); + + GemFireSession session = this.sessionSerializer.deserialize(mockDataInput); + + Set expectedAttributeNames = + asSet("attrOne", "attrTwo", FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); + + assertThat(session.getId()).isEqualTo(expectedSessionId); + assertThat(session.getCreationTime()).isEqualTo(Instant.ofEpochMilli(expectedCreationTime)); + assertThat(session.getLastAccessedTime()).isEqualTo(Instant.ofEpochMilli(expectedLastAccessedTime)); + assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds)); + assertThat(session.getPrincipalName()).isEqualTo(expectedPrincipalName); + assertThat(session.hasDelta()).isFalse(); + assertThat(session.getAttributeNames()).hasSize(3); + assertThat(session.getAttributeNames()).containsAll(expectedAttributeNames); + assertThat(session.getAttribute("attrOne")).isEqualTo("testOne"); + assertThat(session.getAttribute("attrTwo")).isEqualTo("testTwo"); + assertThat(session.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME)) + .isEqualTo(expectedPrincipalName); + + verify(mockDataInput, times(2)).readUTF(); + verify(mockDataInput, times(3)).readLong(); + verify(mockDataInput, times(1)).readInt(); + } + + @Test + public void sessionToDataThenFromDataWhenPrincipalNameIsNullGetsHandledProperly() + throws ClassNotFoundException, IOException { + + Instant beforeOrAtCreationTime = Instant.now(); + + GemFireSession expectedSession = GemFireSession.create(); + + assertThat(expectedSession.getId()).isNotNull(); + assertThat(expectedSession.getCreationTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); + assertThat(expectedSession.getLastAccessedTime().compareTo(beforeOrAtCreationTime)).isGreaterThanOrEqualTo(0); + assertThat(expectedSession.getMaxInactiveInterval()).isEqualTo(Duration.ZERO); + assertThat(expectedSession.getPrincipalName()).isNull(); + + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + + doAnswer(invocation -> null).when(this.sessionSerializer).serializeObject(any(), any(DataOutput.class)); + + doAnswer(invocation -> GemFireSessionAttributes.create()) + .when(this.sessionSerializer).deserializeObject(any(DataInput.class)); + + this.sessionSerializer.serialize(expectedSession, new DataOutputStream(outBytes)); + + GemFireSession deserializedSession = + this.sessionSerializer.deserialize(new DataInputStream(new ByteArrayInputStream(outBytes.toByteArray()))); + + assertThat(deserializedSession).isEqualTo(expectedSession); + assertThat(deserializedSession.getCreationTime()).isEqualTo(expectedSession.getCreationTime()); + assertThat(deserializedSession.getLastAccessedTime()).isEqualTo(expectedSession.getLastAccessedTime()); + assertThat(deserializedSession.getMaxInactiveInterval()).isEqualTo(expectedSession.getMaxInactiveInterval()); + assertThat(deserializedSession.getPrincipalName()).isNull(); + + verify(this.sessionSerializer, times(1)) + .serializeObject(eq(expectedSession.getAttributes()), isA(DataOutput.class)); + + verify(this.sessionSerializer, times(1)).deserializeObject(isA(DataInput.class)); + } +} diff --git a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTest.java b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTests.java similarity index 99% rename from spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTest.java rename to spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTests.java index 9f2fe84..da6aae0 100644 --- a/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTest.java +++ b/spring-session-data-geode/src/test/java/org/springframework/session/data/gemfire/support/GemFireUtilsTests.java @@ -47,7 +47,7 @@ import org.apache.geode.cache.client.ClientRegionShortcut; * @see org.mockito.Mockito * @see org.springframework.session.data.gemfire.support.GemFireUtils */ -public class GemFireUtilsTest { +public class GemFireUtilsTests { @Test public void closeNonNullCloseableSuccessfullyReturnsTrue() throws IOException {