This is an automated email from the ASF dual-hosted git repository. ashapkin pushed a commit to branch ignite-18302 in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git
commit 4e8a5b761224f3bebd11c66677f5a9972d137d12 Author: Alexandr Shapkin <ashap...@gridgain.com> AuthorDate: Fri Jul 7 01:56:36 2023 +0300 ignite-18302: ignite-spring-sessions IgniteSession serialization drags its parent class --- .../sessions/IgniteIndexedSessionRepository.java | 217 ++----------------- .../ignite/spring/sessions/IgniteSession.java | 239 +++++++++++++++++++++ 2 files changed, 258 insertions(+), 198 deletions(-) diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java index 0a679345..277519be 100644 --- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java +++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java @@ -18,13 +18,10 @@ package org.apache.ignite.spring.sessions; */ import java.time.Duration; -import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Set; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -44,9 +41,7 @@ import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; -import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.internal.GridDirectTransient; import org.springframework.context.ApplicationEventPublisher; import org.springframework.session.DelegatingIndexResolver; import org.springframework.session.FindByIndexNameSessionRepository; @@ -96,18 +91,15 @@ import org.springframework.util.Assert; * */ public class IgniteIndexedSessionRepository - implements FindByIndexNameSessionRepository<IgniteIndexedSessionRepository.IgniteSession>, - CacheEntryCreatedListener<String, IgniteIndexedSessionRepository.IgniteSession>, - CacheEntryRemovedListener<String, IgniteIndexedSessionRepository.IgniteSession>, - CacheEntryExpiredListener<String, IgniteIndexedSessionRepository.IgniteSession> { + implements FindByIndexNameSessionRepository<IgniteSession>, + CacheEntryCreatedListener<String, IgniteSession>, + CacheEntryRemovedListener<String, IgniteSession>, + CacheEntryExpiredListener<String, IgniteSession> { /** * The default name of map used by Spring Session to store sessions. */ public static final String DEFAULT_SESSION_MAP_NAME = "spring:session:sessions"; - /** */ - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - /** */ private static final Log logger = LogFactory.getLog(IgniteIndexedSessionRepository.class); @@ -125,7 +117,7 @@ public class IgniteIndexedSessionRepository private Integer defaultMaxInactiveInterval; /** */ - private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>()); + /** */ private String sessionMapName = DEFAULT_SESSION_MAP_NAME; @@ -253,23 +245,23 @@ public class IgniteIndexedSessionRepository if (this.defaultMaxInactiveInterval != null) cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval)); - IgniteSession session = new IgniteSession(cached, true); + IgniteSession session = new IgniteSession(cached, true, saveMode); session.flushImmediateIfNecessary(); return session; } /** */ - @Override public void save(IgniteSession session) { - if (session.isNew) + @Override public static void save(IgniteSession session) { + if (session.isNew()) ttlSessions(session.getMaxInactiveInterval()).put(session.getId(), session); - else if (session.sessionIdChanged) { - this.sessions.remove(session.originalId); - session.originalId = session.getId(); + else if (session.isSessionChanged()) { + this.sessions.remove(session.getOriginalId()); + session.replaceOriginalId(); ttlSessions(session.getMaxInactiveInterval()).put(session.getId(), session); } else if (session.hasChanges()) { - if (session.maxInactiveIntervalChanged) { + if (session.isMaxInactiveIntervalChanged()) { ttlSessions(session.getMaxInactiveInterval()).replace(session.getId(), session); } else { @@ -289,7 +281,8 @@ public class IgniteIndexedSessionRepository deleteById(saved.getId()); return null; } - saved.isNew = false; + //I suppose that's redundant + //saved.isNew = false; return saved; } @@ -311,12 +304,14 @@ public class IgniteIndexedSessionRepository final List<List<?>> sessions = cursor.getAll(); + //this code is a bullshit + Map<String, IgniteSession> sessionMap = new HashMap<>(sessions.size()); sessions.forEach((List<?> res) -> { final MapSession session = (MapSession)res.get(0); - final IgniteSession value = new IgniteSession(session, false); - value.principal = (String)res.get(1); + final String principal = (String)res.get(1); + final IgniteSession value = new IgniteSession(session, false, saveMode, principal); sessionMap.put(session.getId(), value); }); @@ -328,7 +323,7 @@ public class IgniteIndexedSessionRepository throws CacheEntryListenerException { events.forEach((event) -> { IgniteSession session = event.getValue(); - if (session.getId().equals(session.getDelegate().getOriginalId())) { + if (session.getId().equals(session.getCached().getOriginalId())) { if (logger.isDebugEnabled()) logger.debug("Session created with id: " + session.getId()); @@ -379,178 +374,4 @@ public class IgniteIndexedSessionRepository private static TouchedExpiryPolicy createPolicy(Duration duration) { return new TouchedExpiryPolicy(new javax.cache.expiry.Duration(TimeUnit.SECONDS, duration.getSeconds())); } - - /** - * A custom implementation of {@link Session} that uses a {@link MapSession} as the - * basis for its mapping. It keeps track if changes have been made since last save. - */ - final class IgniteSession implements Session { - - /** */ - @QuerySqlField - private final MapSession delegate; - - /** */ - @GridDirectTransient - private boolean isNew; - - /** */ - @GridDirectTransient - private boolean sessionIdChanged; - - /** */ - @GridDirectTransient - private boolean lastAccessedTimeChanged; - - /** */ - @GridDirectTransient - private boolean maxInactiveIntervalChanged; - - /** */ - @GridDirectTransient - private String originalId; - - /** */ - @GridDirectTransient - private Map<String, Object> delta = new HashMap<>(); - - /** */ - @QuerySqlField(index = true) - private String principal; - - /** - * @param cached Map session. - * @param isNew Is new flag. - */ - IgniteSession(MapSession cached, boolean isNew) { - this.delegate = cached; - this.isNew = isNew; - this.originalId = cached.getId(); - if (this.isNew || (IgniteIndexedSessionRepository.this.saveMode == SaveMode.ALWAYS)) - getAttributeNames() - .forEach((attributeName) -> this.delta.put(attributeName, cached.getAttribute(attributeName))); - - } - - /** */ - @Override public void setLastAccessedTime(Instant lastAccessedTime) { - this.delegate.setLastAccessedTime(lastAccessedTime); - this.lastAccessedTimeChanged = true; - flushImmediateIfNecessary(); - } - - /** */ - @Override public boolean isExpired() { - return this.delegate.isExpired(); - } - - /** */ - @Override public Instant getCreationTime() { - return this.delegate.getCreationTime(); - } - - /** */ - @Override public String getId() { - return this.delegate.getId(); - } - - /** */ - @Override public String changeSessionId() { - String newSessionId = this.delegate.changeSessionId(); - this.sessionIdChanged = true; - return newSessionId; - } - - /** */ - @Override public Instant getLastAccessedTime() { - return this.delegate.getLastAccessedTime(); - } - - /** */ - @Override public void setMaxInactiveInterval(Duration interval) { - this.delegate.setMaxInactiveInterval(interval); - this.maxInactiveIntervalChanged = true; - flushImmediateIfNecessary(); - } - - /** */ - @Override public Duration getMaxInactiveInterval() { - return this.delegate.getMaxInactiveInterval(); - } - - /** */ - @Override public <T> T getAttribute(String attributeName) { - T attributeValue = this.delegate.getAttribute(attributeName); - if (attributeValue != null - && IgniteIndexedSessionRepository.this.saveMode.equals(SaveMode.ON_GET_ATTRIBUTE)) - this.delta.put(attributeName, attributeValue); - - return attributeValue; - } - - /** */ - @Override public Set<String> getAttributeNames() { - return this.delegate.getAttributeNames(); - } - - /** */ - @Override public void setAttribute(String attributeName, Object attributeValue) { - this.delegate.setAttribute(attributeName, attributeValue); - this.delta.put(attributeName, attributeValue); - if (SPRING_SECURITY_CONTEXT.equals(attributeName)) { - Map<String, String> indexes = IgniteIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this); - String principal = (attributeValue != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null; - this.delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal); - this.principal = principal; - } - flushImmediateIfNecessary(); - } - - /** */ - @Override public void removeAttribute(String attributeName) { - setAttribute(attributeName, null); - } - - /** */ - MapSession getDelegate() { - return this.delegate; - } - - /** */ - boolean hasChanges() { - return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged || !this.delta.isEmpty()); - } - - /** */ - void clearChangeFlags() { - this.isNew = false; - this.lastAccessedTimeChanged = false; - this.sessionIdChanged = false; - this.maxInactiveIntervalChanged = false; - this.delta.clear(); - } - - /** */ - private void flushImmediateIfNecessary() { - if (IgniteIndexedSessionRepository.this.flushMode == FlushMode.IMMEDIATE) - IgniteIndexedSessionRepository.this.save(this); - } - - /** */ - @Override public boolean equals(Object o) { - if (this == o) - return true; - - if (o == null || getClass() != o.getClass()) - return false; - - IgniteSession session = (IgniteSession)o; - return this.delegate.equals(session.delegate); - } - - /** */ - @Override public int hashCode() { - return Objects.hash(this.delegate); - } - } } diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java new file mode 100644 index 00000000..28157da5 --- /dev/null +++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java @@ -0,0 +1,239 @@ +package org.apache.ignite.spring.sessions; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.internal.GridDirectTransient; +import org.springframework.session.DelegatingIndexResolver; +import org.springframework.session.FlushMode; +import org.springframework.session.IndexResolver; +import org.springframework.session.MapSession; +import org.springframework.session.PrincipalNameIndexResolver; +import org.springframework.session.SaveMode; +import org.springframework.session.Session; + +import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; + +/** + * A custom implementation of {@link Session} that uses a {@link MapSession} as the + * basis for its mapping. It keeps track if changes have been made since last save. + */ +final class IgniteSession implements Session { + + /** */ + private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; + + /** */ + private static IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>()); + + /** */ + @QuerySqlField + private final MapSession cached; + + /** */ + @GridDirectTransient + private boolean isNew; + + /** */ + @GridDirectTransient + private boolean sessionIdChanged; + + /** */ + @GridDirectTransient + private boolean lastAccessedTimeChanged; + + /** */ + @GridDirectTransient + private boolean attributesChanged; + + /** */ + @GridDirectTransient + private boolean maxInactiveIntervalChanged; + + /** */ + @GridDirectTransient + private String originalId; + + /** */ + @QuerySqlField(index = true) + private String principal; + + /** */ + @GridDirectTransient + private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE; + + /** + * @param cached Map session. + * @param isNew Is new flag. + * @param saveMode Save mode. + */ + IgniteSession(MapSession cached, boolean isNew, SaveMode saveMode) { + this.cached = cached; + this.isNew = isNew; + this.originalId = cached.getId(); + this.saveMode = saveMode; + if (this.isNew || saveMode == SaveMode.ALWAYS) + this.attributesChanged = true; + + } + + /** + * @param cached Map session. + * @param isNew Is new flag. + * @param saveMode Save mode. + * @param principal Principal. + */ + IgniteSession(MapSession cached, boolean isNew, SaveMode saveMode, String principal) + { + this(cached, isNew, saveMode); + this.principal = principal; + } + + /** */ + @Override public void setLastAccessedTime(Instant lastAccessedTime) { + this.cached.setLastAccessedTime(lastAccessedTime); + this.lastAccessedTimeChanged = true; + flushImmediateIfNecessary(); + } + + /** */ + @Override public boolean isExpired() { + return this.cached.isExpired(); + } + + /** */ + @Override public Instant getCreationTime() { + return this.cached.getCreationTime(); + } + + /** */ + @Override public String getId() { + return this.cached.getId(); + } + + /** */ + @Override public String changeSessionId() { + String newSessionId = this.cached.changeSessionId(); + this.sessionIdChanged = true; + return newSessionId; + } + + /** */ + @Override public Instant getLastAccessedTime() { + return this.cached.getLastAccessedTime(); + } + + /** */ + @Override public void setMaxInactiveInterval(Duration interval) { + this.cached.setMaxInactiveInterval(interval); + this.maxInactiveIntervalChanged = true; + flushImmediateIfNecessary(); + } + + /** */ + @Override public Duration getMaxInactiveInterval() { + return this.cached.getMaxInactiveInterval(); + } + + /** */ + @Override public <T> T getAttribute(String attributeName) { + T attributeValue = this.cached.getAttribute(attributeName); + if (attributeValue != null + && (saveMode.equals(SaveMode.ON_GET_ATTRIBUTE) || saveMode.equals(SaveMode.ALWAYS))) + attributesChanged = true; + + return attributeValue; + } + + /** */ + @Override public Set<String> getAttributeNames() { + return this.cached.getAttributeNames(); + } + + /** */ + @Override public void setAttribute(String attributeName, Object attributeValue) { + cached.setAttribute(attributeName, attributeValue); + attributesChanged = true; + if (SPRING_SECURITY_CONTEXT.equals(attributeName)) { + Map<String, String> indexes = indexResolver.resolveIndexesFor(this); + String principal = (attributeValue != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null; + cached.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal); + this.principal = principal; + } + flushImmediateIfNecessary(); + } + + /** */ + @Override public void removeAttribute(String attributeName) { + setAttribute(attributeName, null); + } + + /** */ + MapSession getCached() { + return this.cached; + } + + /** */ + boolean hasChanges() { + return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged || attributesChanged); + } + + /** */ + void clearChangeFlags() { + isNew = false; + lastAccessedTimeChanged = false; + sessionIdChanged = false; + maxInactiveIntervalChanged = false; + attributesChanged = false; + } + + /** */ + private void flushImmediateIfNecessary() { + if (IgniteIndexedSessionRepository.this.flushMode == FlushMode.IMMEDIATE) + IgniteIndexedSessionRepository.this.save(this); + } + + /** */ + public boolean isNew() { + return isNew; + } + + /** */ + public boolean isSessionChanged(){ + return sessionIdChanged; + } + + /** */ + public String getOriginalId(){ + return originalId; + } + + protected void replaceOriginalId(){ + originalId = getId(); + } + + public boolean isMaxInactiveIntervalChanged(){ + return maxInactiveIntervalChanged; + } + + /** */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + IgniteSession session = (IgniteSession)o; + return this.cached.equals(session.cached); + } + + /** */ + @Override public int hashCode() { + return Objects.hash(this.cached); + } +} \ No newline at end of file