Apply the configured IsDirtyPredicate strategy interface implementation to appliation domain objects stored in Session Attributes.

Resolves gh-17.
This commit is contained in:
John Blum
2018-12-17 18:40:17 -08:00
parent 545a9fbff1
commit 8e50d365f6
4 changed files with 432 additions and 154 deletions

View File

@@ -35,6 +35,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
@@ -59,6 +60,7 @@ import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.data.gemfire.support.IsDirtyPredicate;
import org.springframework.session.data.gemfire.support.SessionIdHolder;
import org.springframework.session.data.gemfire.support.SessionUtils;
import org.springframework.session.events.AbstractSessionEvent;
@@ -110,20 +112,27 @@ public abstract class AbstractGemFireOperationsSessionRepository
private static final boolean DEFAULT_REGISTER_INTEREST_ENABLED = false;
private static final boolean DEFAULT_REGISTER_INTEREST_RECEIVE_VALUES = true;
// TODO - refactor and use non-static variable
// TODO - use non-static variable
private static final AtomicBoolean usingDataSerialization = new AtomicBoolean(false);
private static final Duration DEFAULT_MAX_INACTIVE_INTERVAL =
Duration.ofSeconds(GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS);
private static final InterestResultPolicy DEFAULT_REGISTER_INTEREST_RESULT_POLICY = InterestResultPolicy.NONE;
private static final IsDirtyPredicate DEFAULT_IS_DIRTY_PREDICATE =
GemFireHttpSessionConfiguration.DEFAULT_IS_DIRTY_PREDICATE;
private boolean registerInterestEnabled = DEFAULT_REGISTER_INTEREST_ENABLED;
private ApplicationEventPublisher applicationEventPublisher = event -> {};
private Duration maxInactiveInterval =
Duration.ofSeconds(GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS);
private Duration maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
private final GemfireOperations template;
private IsDirtyPredicate dirtyPredicate = DEFAULT_IS_DIRTY_PREDICATE;
private final Log logger = newLogger();
private final Region<Object, Session> sessions;
@@ -213,6 +222,17 @@ public abstract class AbstractGemFireOperationsSessionRepository
return sessionsRegion;
}
/**
* Constructs a new instance of {@link Log} using Apache Commons {@link LogFactory}.
*
* @return a new instance of {@link Log} constructed from Apache commons-logging {@link LogFactory}.
* @see org.apache.commons.logging.LogFactory#getLog(Class)
* @see org.apache.commons.logging.Log
*/
private Log newLogger() {
return LogFactory.getLog(getClass());
}
/**
* Constructs a new instance of {@link SessionEventHandlerCacheListenerAdapter}.
*
@@ -233,17 +253,6 @@ public abstract class AbstractGemFireOperationsSessionRepository
return new SessionIdInterestRegisteringCacheListener(this);
}
/**
* Constructs a new instance of {@link Log} using Apache Commons {@link LogFactory}.
*
* @return a new instance of {@link Log} constructed from Apache commons-logging {@link LogFactory}.
* @see org.apache.commons.logging.LogFactory#getLog(Class)
* @see org.apache.commons.logging.Log
*/
private Log newLogger() {
return LogFactory.getLog(getClass());
}
/**
* Sets the configured {@link ApplicationEventPublisher} used to publish {@link Session}
* {@link AbstractSessionEvent events} corresponding to Apache Geode/Pivotal GemFire cache events.
@@ -280,11 +289,40 @@ public abstract class AbstractGemFireOperationsSessionRepository
* used to store and manage {@link Session} data.
* @see #getSessionsRegion()
*/
// TODO - refactor and rename to SessionRegionName
// TODO - rename to SessionRegionName
protected String getFullyQualifiedRegionName() {
return getSessionsRegion().getFullPath();
}
/**
* Configures the {@link IsDirtyPredicate} strategy interface used to determine whether the users' application
* domain objects are dirty or not.
*
* @param dirtyPredicate {@link IsDirtyPredicate} strategy interface implementation used to determine whether
* the users' application domain objects are dirty or not.
* @see org.springframework.session.data.gemfire.support.IsDirtyPredicate
*/
public void setIsDirtyPredicate(IsDirtyPredicate dirtyPredicate) {
this.dirtyPredicate = dirtyPredicate;
}
/**
* Returns the configured {@link IsDirtyPredicate} strategy interface implementation used to determine whether
* the users' application domain objects are dirty or not.
*
* Defaults to {@link GemFireHttpSessionConfiguration#DEFAULT_IS_DIRTY_PREDICATE}.
*
* @return the configured {@link IsDirtyPredicate} strategy interface used to determine whether
* the users' application domain objects are dirty or not.
* @see org.springframework.session.data.gemfire.support.IsDirtyPredicate
*/
public IsDirtyPredicate getIsDirtyPredicate() {
return this.dirtyPredicate != null
? this.dirtyPredicate
: DEFAULT_IS_DIRTY_PREDICATE;
}
/**
* Return a reference to the {@link Log} used to log messages.
*
@@ -431,6 +469,16 @@ public abstract class AbstractGemFireOperationsSessionRepository
.orElse(session);
}
protected @Nullable Session configure(@Nullable Session session) {
return Optional.ofNullable(session)
.filter(GemFireSession.class::isInstance)
.map(GemFireSession.class::cast)
.map(it -> it.configureWith(getMaxInactiveInterval()))
.<Session>map(it -> it.configureWith(getIsDirtyPredicate()))
.orElse(session);
}
/**
* Deletes the given {@link Session} from Apache Geode / Pivotal GemFire.
*
@@ -510,7 +558,7 @@ public abstract class AbstractGemFireOperationsSessionRepository
* @see org.apache.geode.cache.Region#registerInterest(Object, InterestResultPolicy, boolean, boolean)
* @see #isRegisterInterestEnabled()
*/
protected void registerInterest(Object sessionId) {
protected void registerInterest(@Nullable Object sessionId) {
Optional.ofNullable(sessionId)
.filter(it -> this.isRegisterInterestEnabled())
@@ -592,7 +640,9 @@ public abstract class AbstractGemFireOperationsSessionRepository
@Override
protected DeltaCapableGemFireSessionAttributes newSessionAttributes(Object lock) {
return new DeltaCapableGemFireSessionAttributes(lock);
return new DeltaCapableGemFireSessionAttributes(lock)
.configureWith(getIsDirtyPredicate());
}
public synchronized void toDelta(DataOutput out) throws IOException {
@@ -618,52 +668,29 @@ public abstract class AbstractGemFireOperationsSessionRepository
*
* @see java.lang.Comparable
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes
*/
@SuppressWarnings("serial")
public static class GemFireSession<T extends GemFireSessionAttributes> implements Comparable<Session>, Session {
protected static final Duration DEFAULT_MAX_INACTIVE_INTERVAL = Duration.ZERO;
protected static final String GEMFIRE_SESSION_TO_STRING =
"{ @type = %1$s, id = %2$s, creationTime = %3$s, lastAccessedTime = %4$s, maxInactiveInterval = %5$s, principalName = %6$s }";
protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
/**
* Factory method used to create a new instance of {@link GemFireSession} initialized with
* the {@link #DEFAULT_MAX_INACTIVE_INTERVAL}.
* Factory method used to construct a new, default instance of {@link GemFireSession}.
*
* @param <T> {@link Class Sub-type} of {@link GemFireSessionAttributes}.
* @return new {@link GemFireSession}.
* @see #create(Duration)
*/
public static <T extends GemFireSessionAttributes> GemFireSession<T> create() {
return create(DEFAULT_MAX_INACTIVE_INTERVAL);
}
/**
* Factory method used to create a new instance of {@link GemFireSession} initialized with
* the given {@link Duration max inactive interval}.
*
* @param <T> {@link Class Sub-type} of {@link GemFireSessionAttributes}.
* @param maxInactiveInterval {@link Duration} specifying the max inactive interval before
* this {@link Session} will expire.
* @return a new instance of {@link GemFireSession} initialized with
* the given {@link Duration max inactive interval}.
* @return a new {@link GemFireSession}.
* @see #isUsingDataSerialization()
* @see java.time.Duration
*/
@SuppressWarnings("unchecked")
// TODO - remove
public static <T extends GemFireSessionAttributes> GemFireSession<T> create(Duration maxInactiveInterval) {
public static <T extends GemFireSessionAttributes> GemFireSession<T> create() {
GemFireSession session = isUsingDataSerialization()
? new DeltaCapableGemFireSession()
return isUsingDataSerialization()
? (GemFireSession<T>) new DeltaCapableGemFireSession()
: new GemFireSession();
session.setMaxInactiveInterval(maxInactiveInterval);
return session;
}
/**
@@ -682,12 +709,12 @@ public abstract class AbstractGemFireOperationsSessionRepository
}
/**
* Returns the given {@link Session} if the {@link Session} is a {@link GemFireSession} or return a copy
* of the given {@link Session} as a {@link GemFireSession}.
* Returns the given {@link Session} if the {@link Session} is a {@link GemFireSession}
* or return a copy of the given {@link Session} as a {@link GemFireSession}.
*
* @param session {@link Session} to evaluate and possibly copy.
* @return the given {@link Session} if the {@link Session} is a {@link GemFireSession} or return a copy
* of the given {@link Session} as a {@link GemFireSession}
* @return the given {@link Session} if the {@link Session} is a {@link GemFireSession}
* or return a copy of the given {@link Session} as a {@link GemFireSession}.
* @see #copy(Session)
*/
@SuppressWarnings("unchecked")
@@ -700,8 +727,11 @@ public abstract class AbstractGemFireOperationsSessionRepository
private Duration maxInactiveInterval;
private final Instant creationTime;
private Instant lastAccessedTime;
private transient IsDirtyPredicate dirtyPredicate = DEFAULT_IS_DIRTY_PREDICATE;
private transient final SpelExpressionParser parser = new SpelExpressionParser();
private String id;
@@ -734,7 +764,7 @@ public abstract class AbstractGemFireOperationsSessionRepository
this.id = validateSessionId(id);
this.creationTime = Instant.now();
this.lastAccessedTime = this.creationTime;
this.maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL;
this.maxInactiveInterval = Duration.ZERO;
}
/**
@@ -761,10 +791,13 @@ public abstract class AbstractGemFireOperationsSessionRepository
* @param lock {@link Object} used as the mutex for concurrent access and Thread-safety.
* @return the new {@link GemFireSessionAttributes}.
* @see GemFireSessionAttributes
* @see #getIsDirtyPredicate()
*/
@SuppressWarnings("unchecked")
protected T newSessionAttributes(Object lock) {
return (T) new GemFireSessionAttributes(lock);
return (T) new GemFireSessionAttributes(lock)
.configureWith(getIsDirtyPredicate());
}
/**
@@ -815,6 +848,17 @@ public abstract class AbstractGemFireOperationsSessionRepository
getAttributes().commit();
}
/**
* Determines whether this {@link GemFireSession} has any changes (i.e. a delta).
*
* Changes exist if this {@link GemFireSession GemFireSession's} {@link #getId() ID},
* {@link #getLastAccessedTime() last accessed time}, {@link #getMaxInactiveInterval() max inactive interval}
* or any of these {@link #getAttributeNames() attributes} have changed.
*
* @return a boolean value indicating whether this {@link GemFireSession} has any changes.
* @see GemFireSessionAttributes#hasDelta()
* @see #getAttributes()
*/
public synchronized boolean hasDelta() {
return this.delta || getAttributes().hasDelta();
}
@@ -877,6 +921,17 @@ public abstract class AbstractGemFireOperationsSessionRepository
return !isExpirationDisabled(duration);
}
protected synchronized void setIsDirtyPredicate(IsDirtyPredicate dirtyPredicate) {
this.dirtyPredicate = dirtyPredicate;
}
protected synchronized IsDirtyPredicate getIsDirtyPredicate() {
return this.dirtyPredicate != null
? this.dirtyPredicate
: DEFAULT_IS_DIRTY_PREDICATE;
}
private boolean isLastAccessedTimeValid(Instant lastAccessedTime) {
return lastAccessedTime != null;
}
@@ -904,8 +959,9 @@ public abstract class AbstractGemFireOperationsSessionRepository
public synchronized Duration getMaxInactiveInterval() {
return Optional.ofNullable(this.maxInactiveInterval)
.orElse(DEFAULT_MAX_INACTIVE_INTERVAL);
return this.maxInactiveInterval != null
? this.maxInactiveInterval
: Duration.ZERO;
}
public synchronized void setPrincipalName(String principalName) {
@@ -931,6 +987,36 @@ public abstract class AbstractGemFireOperationsSessionRepository
return principalName;
}
/**
* Builder method to configure the {@link Duration max inactive interval} before this {@link GemFireSession}
* will expire.
*
* @param maxInactiveInterval {@link Duration} specifying the maximum time this {@link GemFireSession}
* can remain inactive before expiration.
* @return this {@link GemFireSession}.
* @see #setMaxInactiveInterval(Duration)
* @see java.time.Duration
*/
public GemFireSession<T> configureWith(Duration maxInactiveInterval) {
setMaxInactiveInterval(maxInactiveInterval);
return this;
}
/**
* Builder method to configure the {@link IsDirtyPredicate} strategy interface implementation to determine
* whether users' {@link Object application domain objects} stored in this {@link GemFireSession} are dirty.
*
* @param dirtyPredicate {@link IsDirtyPredicate} strategy interface implementation that determines whether
* the users' {@link Object application domain objects} stored in this {@link GemFireSession} are dirty.
* @return this {@link GemFireSession}.
* @see org.springframework.session.data.gemfire.support.IsDirtyPredicate
* @see #setIsDirtyPredicate(IsDirtyPredicate)
*/
public GemFireSession<T> configureWith(IsDirtyPredicate dirtyPredicate) {
setIsDirtyPredicate(dirtyPredicate);
return this;
}
@SuppressWarnings("all")
@Override
public int compareTo(Session session) {
@@ -971,7 +1057,6 @@ public abstract class AbstractGemFireOperationsSessionRepository
}
}
@SuppressWarnings("unused")
public static class DeltaCapableGemFireSessionAttributes extends GemFireSessionAttributes implements Delta {
private transient final Set<String> sessionAttributeDeltas = new HashSet<>();
@@ -990,38 +1075,12 @@ public abstract class AbstractGemFireOperationsSessionRepository
}
@Override
public Object setAttribute(String attributeName, Object attributeValue) {
protected BiFunction<String, Object, Boolean> sessionAttributesChangeInterceptor() {
synchronized (getLock()) {
if (attributeValue != null) {
Object previousAttributeValue = super.setAttribute(attributeName, attributeValue);
if (!attributeValue.equals(previousAttributeValue)) {
getSessionAttributeDeltas().add(attributeName);
}
return previousAttributeValue;
}
else {
return removeAttribute(attributeName);
}
}
}
@Override
public Object removeAttribute(String attributeName) {
synchronized (getLock()) {
return Optional.ofNullable(super.removeAttribute(attributeName))
.map(previousAttributeValue -> {
getSessionAttributeDeltas().add(attributeName);
return previousAttributeValue;
})
.orElse(null);
}
return (attributeName, attributeValue) -> {
getSessionAttributeDeltas().add(attributeName);
return true;
};
}
public void toDelta(DataOutput out) throws IOException {
@@ -1116,6 +1175,8 @@ public abstract class AbstractGemFireOperationsSessionRepository
private transient boolean delta = false;
private transient IsDirtyPredicate dirtyPredicate = DEFAULT_IS_DIRTY_PREDICATE;
private transient final Map<String, Object> sessionAttributes = new HashMap<>();
private transient final Object lock;
@@ -1149,6 +1210,22 @@ public abstract class AbstractGemFireOperationsSessionRepository
return this.lock;
}
protected void setIsDirtyPredicate(IsDirtyPredicate dirtyPredicate) {
synchronized (getLock()) {
this.dirtyPredicate = dirtyPredicate;
}
}
protected IsDirtyPredicate getIsDirtyPredicate() {
synchronized (getLock()) {
return this.dirtyPredicate != null
? this.dirtyPredicate
: DEFAULT_IS_DIRTY_PREDICATE;
}
}
public Object setAttribute(String attributeName, Object attributeValue) {
synchronized (getLock()) {
@@ -1162,7 +1239,8 @@ public abstract class AbstractGemFireOperationsSessionRepository
Object previousAttributeValue = this.sessionAttributes.put(attributeName, attributeValue);
this.delta |= !attributeValue.equals(previousAttributeValue);
this.delta |= getIsDirtyPredicate().isDirty(previousAttributeValue, attributeValue)
&& sessionAttributesChangeInterceptor().apply(attributeName, attributeValue);
return previousAttributeValue;
}
@@ -1171,7 +1249,8 @@ public abstract class AbstractGemFireOperationsSessionRepository
synchronized (getLock()) {
this.delta |= this.sessionAttributes.containsKey(attributeName);
this.delta |= this.sessionAttributes.containsKey(attributeName)
&& sessionAttributesChangeInterceptor().apply(attributeName, null);
return this.sessionAttributes.remove(attributeName);
}
@@ -1214,6 +1293,10 @@ public abstract class AbstractGemFireOperationsSessionRepository
}
}
protected BiFunction<String, Object, Boolean> sessionAttributesChangeInterceptor() {
return (attributeName, attributeValue) -> true;
}
protected void commit() {
synchronized (getLock()) {
@@ -1221,6 +1304,12 @@ public abstract class AbstractGemFireOperationsSessionRepository
}
}
@SuppressWarnings("unchecked")
public <T extends GemFireSessionAttributes> T configureWith(IsDirtyPredicate dirtyPredicate) {
setIsDirtyPredicate(dirtyPredicate);
return (T) this;
}
public void from(Session session) {
synchronized (getLock()) {

View File

@@ -16,7 +16,6 @@
package org.springframework.session.data.gemfire;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@@ -66,13 +65,13 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* Constructs a new {@link Session} instance backed by GemFire.
*
* @return an instance of {@link Session} backed by GemFire.
* @see AbstractGemFireOperationsSessionRepository.GemFireSession#create(Duration)
* @see AbstractGemFireOperationsSessionRepository.GemFireSession#create()
* @see org.springframework.session.Session
* @see #getMaxInactiveIntervalInSeconds()
* @see #configure(Session)
*/
@NonNull
public Session createSession() {
return GemFireSession.create(getMaxInactiveInterval());
return configure(GemFireSession.create());
}
/**
@@ -86,7 +85,8 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* @see AbstractGemFireOperationsSessionRepository.GemFireSession#from(Session)
* @see org.springframework.session.Session
* @see #commit(Session)
* @see #deleteById(String)
* @see #configure(Session)
* @see #delete(Session)
* @see #registerInterest(Session)
* @see #touch(Session)
*/
@@ -98,7 +98,7 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
if (storedSession != null) {
storedSession = storedSession.isExpired()
? delete(storedSession)
: registerInterest(touch(commit(GemFireSession.from(storedSession))));
: touch(commit(registerInterest(configure(GemFireSession.from(storedSession)))));
}
return storedSession;
@@ -114,9 +114,10 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* (e.g. {@literal username}).
* @return a mapping of {@link Session#getId()} Session IDs} to {@link Session} objects.
* @see org.springframework.session.Session
* @see #prepareQuery(String)
* @see java.util.Map
* @see #prepareQuery(String)
* @see #commit(Session)
* @see #configure(Session)
* @see #registerInterest(Session)
* @see #touch(Session)
*/
@@ -127,7 +128,8 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
Map<String, Session> sessions = new HashMap<>(results.size());
results.asList().forEach(session -> sessions.put(session.getId(), registerInterest(touch(commit(session)))));
results.asList().forEach(session ->
sessions.put(session.getId(), touch(commit(registerInterest(configure(session))))));
return sessions;
}
@@ -139,6 +141,7 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* @param indexName a String indicating the name of the indexed Session attribute.
* @return an appropriate Pivotal GemFire OQL statement for querying on a particular indexed
* Session attribute.
* @see #getFullyQualifiedRegionName()
*/
protected String prepareQuery(String indexName) {
@@ -159,6 +162,8 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* @param session the {@link Session} to save.
* @see org.springframework.data.gemfire.GemfireOperations#put(Object, Object)
* @see org.springframework.session.Session
* @see #isNonNullAndDirty(Session)
* @see #doSave(Session)
*/
public void save(@Nullable Session session) {

View File

@@ -86,7 +86,11 @@ import org.springframework.data.gemfire.util.RegionUtils;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.support.DeltaAwareDirtyPredicate;
import org.springframework.session.data.gemfire.support.EqualsDirtyPredicate;
import org.springframework.session.data.gemfire.support.GemFireOperationsSessionRepositorySupport;
import org.springframework.session.data.gemfire.support.IdentityEqualsDirtyPredicate;
import org.springframework.session.data.gemfire.support.IsDirtyPredicate;
import org.springframework.session.data.gemfire.support.SessionIdHolder;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
@@ -336,6 +340,26 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
verify(this.mockRegion, times(1)).getFullPath();
}
@Test
public void setAndGetIsDirtyPredicate() {
assertThat(this.sessionRepository.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
IsDirtyPredicate mockDirtyPredicate = mock(IsDirtyPredicate.class);
this.sessionRepository.setIsDirtyPredicate(mockDirtyPredicate);
assertThat(this.sessionRepository.getIsDirtyPredicate()).isEqualTo(mockDirtyPredicate);
this.sessionRepository.setIsDirtyPredicate(null);
assertThat(this.sessionRepository.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
this.sessionRepository.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
assertThat(this.sessionRepository.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
}
@Test
public void setAndGetMaxInactiveInterval() {
@@ -374,7 +398,7 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
}
@Test
public void maxInactiveIntervalInSecondsAllowsExtremelyLargeAndNegativeValues() {
public void setMaxInactiveIntervalInSecondsAllowsExtremelyLargeAndNegativeValues() {
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds())
.isEqualTo(GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS);
@@ -472,6 +496,44 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
this.sessionRepository.commit(null);
}
@Test
public void configureWithGemFireSession() {
GemFireSession<?> session = GemFireSession.create();
assertThat(session).isNotNull();
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
this.sessionRepository.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
this.sessionRepository.setMaxInactiveIntervalInSeconds(300);
this.sessionRepository.configure(session);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(300));
assertThat(session.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
verify(this.sessionRepository, times(1)).getIsDirtyPredicate();
verify(this.sessionRepository, times(1)).getMaxInactiveInterval();
}
@Test
public void configureWithNull() {
this.sessionRepository.configure(null);
verify(this.sessionRepository, never()).getIsDirtyPredicate();
verify(this.sessionRepository, never()).getMaxInactiveInterval();
}
@Test
public void configureWithSession() {
this.sessionRepository.configure(this.mockSession);
verify(this.sessionRepository, never()).getIsDirtyPredicate();
verify(this.sessionRepository, never()).getMaxInactiveInterval();
}
@Test
public void deleteSessionCallsDeleteSessionById() {
@@ -1902,37 +1964,46 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
}
@Test
public void createNewGemFireSessionWithDefaultMaxInactiveInterval() {
public void createNewGemFireSession() {
assertThat(AbstractGemFireOperationsSessionRepository.isUsingDataSerialization()).isFalse();
Instant testCreationTime = Instant.now();
GemFireSession<?> session = GemFireSession.create();
assertThat(session).isNotNull();
assertThat(session.getId()).isNotNull();
assertThat(session).isNotInstanceOf(DeltaCapableGemFireSession.class);
assertThat(session.getId()).isNotEmpty();
assertThat(session.getCreationTime()).isAfterOrEqualTo(testCreationTime);
assertThat(session.getCreationTime()).isBeforeOrEqualTo(Instant.now());
assertThat(session.hasDelta()).isTrue();
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime());
assertThat(session.getMaxInactiveInterval()).isEqualTo(GemFireSession.DEFAULT_MAX_INACTIVE_INTERVAL);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
assertThat(session.getAttributes()).isNotNull();
assertThat(session.getAttributes()).isEmpty();
}
@Test
public void createNewGemFireSessionWithSpecifiedMaxInactiveInterval() {
public void createNewDeltaCapableGemFireSession() {
this.sessionRepository.setUseDataSerialization(true);
assertThat(AbstractGemFireOperationsSessionRepository.isUsingDataSerialization()).isTrue();
Instant testCreationTime = Instant.now();
Duration maxInactiveInterval = Duration.ofSeconds(120L);
GemFireSession<?> session = GemFireSession.create();
GemFireSession<?> session = GemFireSession.create(maxInactiveInterval);
assertThat(session).isNotNull();
assertThat(session.getId()).isNotNull();
assertThat(session).isInstanceOf(DeltaCapableGemFireSession.class);
assertThat(session.getId()).isNotEmpty();
assertThat(session.getCreationTime()).isAfterOrEqualTo(testCreationTime);
assertThat(session.getCreationTime()).isBeforeOrEqualTo(Instant.now());
assertThat(session.hasDelta()).isTrue();
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime());
assertThat(session.getMaxInactiveInterval()).isEqualTo(maxInactiveInterval);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
assertThat(session.getAttributes()).isNotNull();
assertThat(session.getAttributes()).isEmpty();
}
@@ -2013,6 +2084,16 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
verify(mockSession, times(1)).getAttribute(eq("attributeOne"));
}
@Test
public void fromExistingGemFireSessionIsGemFireSession() {
GemFireSession<?> gemfireSession = GemFireSession.create();
GemFireSession<?> fromGemFireSession = GemFireSession.from(gemfireSession);
assertThat(fromGemFireSession).isSameAs(gemfireSession);
}
@Test
public void fromExistingSessionCopiesSession() {
@@ -2045,16 +2126,6 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
verify(mockSession, never()).getAttribute(anyString());
}
@Test
public void fromExistingGemFireSessionIsGemFireSession() {
GemFireSession<?> gemfireSession = GemFireSession.create();
GemFireSession<?> fromGemFireSession = GemFireSession.from(gemfireSession);
assertThat(fromGemFireSession).isSameAs(gemfireSession);
}
@Test(expected = IllegalArgumentException.class)
public void fromNullSessionThrowsIllegalArgumentException() {
@@ -2070,6 +2141,50 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
}
}
@Test
public void newSessionAttributesIsConfiguredCorrectly() {
GemFireSession<?> session = new GemFireSession<>();
session.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
assertThat(session.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
GemFireSessionAttributes sessionAttributes = session.newSessionAttributes(session);
assertThat(sessionAttributes).isNotNull();
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
assertThat(sessionAttributes.getLock()).isSameAs(session);
}
@Test
public void newDeltaCapableSessionAttributesIsConfiguredCorrectly() {
DeltaCapableGemFireSession session = new DeltaCapableGemFireSession();
session.setIsDirtyPredicate(IdentityEqualsDirtyPredicate.INSTANCE);
assertThat(session.getIsDirtyPredicate()).isEqualTo(IdentityEqualsDirtyPredicate.INSTANCE);
DeltaCapableGemFireSessionAttributes sessionAttributes = session.newSessionAttributes(session);
assertThat(sessionAttributes).isNotNull();
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(IdentityEqualsDirtyPredicate.INSTANCE);
assertThat(sessionAttributes.getLock()).isEqualTo(session);
}
@Test
public void changeSessionIdIsCorrect() {
GemFireSession<?> session = new GemFireSession<>();
String sessionId = session.getId();
assertThat(sessionId).isNotEmpty();
assertThat(session.changeSessionId()).isNotEmpty();
assertThat(session.getId()).isNotEqualTo(sessionId);
}
@Test
public void setGetAndRemoveAttribute() {
@@ -2108,7 +2223,8 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
Duration expectedMaxInactiveIntervalInSeconds = Duration.ofSeconds(-1);
GemFireSession<?> session = GemFireSession.create(expectedMaxInactiveIntervalInSeconds);
GemFireSession<?> session = GemFireSession.create()
.configureWith(expectedMaxInactiveIntervalInSeconds);
assertThat(session).isNotNull();
assertThat(session.getMaxInactiveInterval()).isEqualTo(expectedMaxInactiveIntervalInSeconds);
@@ -2118,25 +2234,23 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
@Test
public void isExpiredWhenMaxInactiveIntervalIsNullReturnsFalse() {
GemFireSession<?> session = GemFireSession.create(null);
GemFireSession<?> session = GemFireSession.create();
assertThat(session).isNotNull();
session.setMaxInactiveInterval(null);
assertThat(session.getMaxInactiveInterval()).isEqualTo(GemFireSession.DEFAULT_MAX_INACTIVE_INTERVAL);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
assertThat(session.isExpired()).isFalse();
}
@Test
public void isExpiredWhenMaxInactiveIntervalIsZeroReturnsFalse() {
Duration expectedMaxInactiveIntervalInSeconds = Duration.ZERO;
GemFireSession<?> session = GemFireSession.create(expectedMaxInactiveIntervalInSeconds);
GemFireSession<?> session = GemFireSession.create();
assertThat(session).isNotNull();
assertThat(session.getMaxInactiveInterval()).isEqualTo(expectedMaxInactiveIntervalInSeconds);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
assertThat(session.isExpired()).isFalse();
}
@@ -2145,7 +2259,8 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
long expectedMaxInactiveIntervalInSeconds = TimeUnit.HOURS.toSeconds(2);
GemFireSession<?> session = GemFireSession.create(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds));
GemFireSession<?> session = GemFireSession.create()
.configureWith(Duration.ofSeconds(expectedMaxInactiveIntervalInSeconds));
assertThat(session).isNotNull();
assertThat(session.getMaxInactiveInterval())
@@ -2164,7 +2279,8 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
Duration maxInactiveInterval = Duration.ofMillis(1);
GemFireSession<?> session = GemFireSession.create(maxInactiveInterval);
GemFireSession<?> session = GemFireSession.create()
.configureWith(maxInactiveInterval);
assertThat(session).isNotNull();
assertThat(session.getMaxInactiveInterval()).isEqualTo(maxInactiveInterval);
@@ -2179,6 +2295,29 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
assertThat(session.isExpired()).isTrue();
}
@Test
public void setAndGetGemFireSessionIsDirtyPredicate() {
GemFireSession<?> session = GemFireSession.create();
assertThat(session).isNotNull();
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
IsDirtyPredicate mockDirtyPredicate = mock(IsDirtyPredicate.class);
session.setIsDirtyPredicate(mockDirtyPredicate);
assertThat(session.getIsDirtyPredicate()).isEqualTo(mockDirtyPredicate);
session.setIsDirtyPredicate(null);
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
session.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
assertThat(session.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
}
@Test
public void setAndGetLastAccessedTime() {
@@ -2271,6 +2410,26 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
assertThat(session.getPrincipalName()).isNull();
}
@Test
public void configuresIsDirtyPredicateReturnsGemFireSession() {
GemFireSession<?> session = new GemFireSession<>();
assertThat(session.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
assertThat(session.configureWith(EqualsDirtyPredicate.INSTANCE)).isSameAs(session);
assertThat(session.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
}
@Test
public void configuresMaxInactiveIntervalReturnsGemFireSession() {
GemFireSession<?> session = new GemFireSession<>();
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ZERO);
assertThat(session.configureWith(Duration.ofSeconds(1))).isSameAs(session);
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(1));
}
@Test
public void sessionToDelta() throws Exception {
@@ -2714,6 +2873,28 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
assertThat(target.<String>getAttribute("attributeTwo")).isEqualTo("testTwo");
}
@Test
public void setAndGetGemFireSessionAttributesIsDirtyPredicate() {
GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes();
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
IsDirtyPredicate mockDirtyPredicate = mock(IsDirtyPredicate.class);
sessionAttributes.setIsDirtyPredicate(mockDirtyPredicate);
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(mockDirtyPredicate);
sessionAttributes.setIsDirtyPredicate(null);
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
sessionAttributes.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
}
@Test
public void sessionAttributesToDelta() throws Exception {
@@ -2750,7 +2931,6 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
reset(mockDataOutput);
sessionAttributes.commit();
sessionAttributes.setAttribute("attributeOne", "testOne");
assertThat(sessionAttributes.hasDelta()).isFalse();
@@ -2893,7 +3073,7 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
}
@Test
public void sessionAttributesHasDeltaWhenSetDoesNotModifyAttributeReturnsFalse() {
public void sessionAttributesHasDeltaWhenSetDoesNotModifyAttributeReturnsTrue() {
GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes();
@@ -2908,7 +3088,7 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
assertThat(sessionAttributes.getAttributeNames()).containsExactly("attributeOne");
assertThat(sessionAttributes.<String>getAttribute("attributeOne")).isEqualTo("testOne");
assertThat(sessionAttributes.hasDelta()).isFalse();
assertThat(sessionAttributes.hasDelta()).isTrue();
sessionAttributes.commit();
@@ -3071,25 +3251,14 @@ public class AbstractGemFireOperationsSessionRepositoryTests {
}
@Test
public void gemfireSessionIsLockForGemFireSessionAttributes() {
public void configuresIsDirtyPredicateReturnsGemFireSessionAttributes() {
GemFireSession session = new GemFireSession();
GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes();
GemFireSessionAttributes sessionAttributes = session.newSessionAttributes(session);
assertThat(sessionAttributes).isNotNull();
assertThat(sessionAttributes.getLock()).isSameAs(session);
}
@Test
public void deltaCapableGemFireSessionIsLockForDeltaCapableGemFirSessionAttributes() {
DeltaCapableGemFireSession session = new DeltaCapableGemFireSession();
DeltaCapableGemFireSessionAttributes sessionAttributes = session.newSessionAttributes(session);
assertThat(sessionAttributes).isNotNull();
assertThat(sessionAttributes.getLock()).isSameAs(session);
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(DeltaAwareDirtyPredicate.INSTANCE);
assertThat(sessionAttributes.<GemFireSessionAttributes>configureWith(EqualsDirtyPredicate.INSTANCE))
.isSameAs(sessionAttributes);
assertThat(sessionAttributes.getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
}
@Test

View File

@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import java.time.Duration;
@@ -61,6 +62,8 @@ import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.data.gemfire.util.RegionUtils;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.SessionEventHandlerCacheListenerAdapter;
import org.springframework.session.data.gemfire.support.EqualsDirtyPredicate;
import org.springframework.session.data.gemfire.support.IdentityEqualsDirtyPredicate;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionDeletedEvent;
@@ -174,14 +177,17 @@ public class GemFireOperationsSessionRepositoryTests {
Instant beforeCreationTime = Instant.now();
this.sessionRepository.setIsDirtyPredicate(EqualsDirtyPredicate.INSTANCE);
Session session = this.sessionRepository.createSession();
assertThat(session).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(session).isInstanceOf(GemFireSession.class);
assertThat(session.getId()).isNotEmpty();
assertThat(session.getAttributeNames()).isEmpty();
assertThat(session.getCreationTime()).isAfterOrEqualTo(beforeCreationTime);
assertThat(session.getCreationTime()).isBeforeOrEqualTo(Instant.now());
assertThat(session.isExpired()).isFalse();
assertThat(((GemFireSession) session).getIsDirtyPredicate()).isEqualTo(EqualsDirtyPredicate.INSTANCE);
assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime());
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
}
@@ -191,18 +197,22 @@ public class GemFireOperationsSessionRepositoryTests {
Instant beforeCreationTime = Instant.now();
this.sessionRepository.setIsDirtyPredicate(IdentityEqualsDirtyPredicate.INSTANCE);
this.sessionRepository.setMaxInactiveIntervalInSeconds(300);
this.sessionRepository.setUseDataSerialization(true);
Session session = this.sessionRepository.createSession();
assertThat(session).isInstanceOf(AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession.class);
assertThat(session).isInstanceOf(DeltaCapableGemFireSession.class);
assertThat(session.getId()).isNotEmpty();
assertThat(session.getAttributeNames()).isEmpty();
assertThat(session.getCreationTime()).isAfterOrEqualTo(beforeCreationTime);
assertThat(session.getCreationTime()).isBeforeOrEqualTo(Instant.now());
assertThat(session.isExpired()).isFalse();
assertThat(((DeltaCapableGemFireSession) session).getIsDirtyPredicate())
.isEqualTo(IdentityEqualsDirtyPredicate.INSTANCE);
assertThat(session.getLastAccessedTime()).isEqualTo(session.getCreationTime());
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS));
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(300));
}
@Test
@@ -245,9 +255,10 @@ public class GemFireOperationsSessionRepositoryTests {
InOrder inOrder = inOrder(sessionRepositorySpy);
inOrder.verify(sessionRepositorySpy, times(1)).configure(eq(actualSession));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(actualSession));
inOrder.verify(sessionRepositorySpy, times(1)).commit(eq(actualSession));
inOrder.verify(sessionRepositorySpy, times(1)).touch(eq(actualSession));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(actualSession));
}
@Test
@@ -337,9 +348,10 @@ public class GemFireOperationsSessionRepositoryTests {
InOrder inOrder = inOrder(sessionRepositorySpy);
inOrder.verify(sessionRepositorySpy, times(1)).configure(eq(mockSession));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSession));
inOrder.verify(sessionRepositorySpy, times(1)).commit(eq(mockSession));
inOrder.verify(sessionRepositorySpy, times(1)).touch(eq(mockSession));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSession));
}
@Test
@@ -385,15 +397,18 @@ public class GemFireOperationsSessionRepositoryTests {
InOrder inOrder = inOrder(sessionRepositorySpy);
inOrder.verify(sessionRepositorySpy, times(1)).configure(eq(mockSessionOne));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionOne));
inOrder.verify(sessionRepositorySpy, times(1)).commit(eq(mockSessionOne));
inOrder.verify(sessionRepositorySpy, times(1)).touch(eq(mockSessionOne));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionOne));
inOrder.verify(sessionRepositorySpy, times(1)).configure(eq(mockSessionTwo));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionTwo));
inOrder.verify(sessionRepositorySpy, times(1)).commit(eq(mockSessionTwo));
inOrder.verify(sessionRepositorySpy, times(1)).touch(eq(mockSessionTwo));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionTwo));
inOrder.verify(sessionRepositorySpy, times(1)).configure(eq(mockSessionThree));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionThree));
inOrder.verify(sessionRepositorySpy, times(1)).commit(eq(mockSessionThree));
inOrder.verify(sessionRepositorySpy, times(1)).touch(eq(mockSessionThree));
inOrder.verify(sessionRepositorySpy, times(1)).registerInterest(eq(mockSessionThree));
}
@Test