diff --git a/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java index 22cbd2a74..8f172ee45 100644 --- a/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java +++ b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -29,6 +29,8 @@ import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; import org.apache.catalina.session.ManagerBase; import org.apache.catalina.util.LifecycleSupport; import org.apache.juli.logging.Log; @@ -63,6 +65,7 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { private ReadMode readMode = ReadMode.REDIS; private UpdateMode updateMode = UpdateMode.DEFAULT; private String keyPrefix = ""; + private boolean broadcastSessionEvents = false; private final String nodeId = UUID.randomUUID().toString(); @@ -75,6 +78,14 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { public void setUpdateMode(String updateMode) { this.updateMode = UpdateMode.valueOf(updateMode); } + + public boolean isBroadcastSessionEvents() { + return broadcastSessionEvents; + } + + public void setBroadcastSessionEvents(boolean replicateSessionEvents) { + this.broadcastSessionEvents = replicateSessionEvents; + } public String getReadMode() { return readMode.toString(); @@ -134,20 +145,19 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { @Override public Session createSession(String sessionId) { - RedissonSession session = (RedissonSession) createEmptySession(); + Session session = super.createSession(sessionId); - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); - - if (sessionId == null) { - sessionId = generateSessionId(); + if (broadcastSessionEvents) { + getTopic().publish(new SessionCreatedMessage(getNodeId(), session.getId())); + session.addSessionListener(new SessionListener() { + @Override + public void sessionEvent(SessionEvent event) { + if (event.getType() == Session.SESSION_DESTROYED_EVENT) { + getTopic().publish(new SessionDestroyedMessage(getNodeId(), session.getId())); + } + } + }); } - - session.setManager(this); - session.setId(sessionId); - return session; } @@ -178,14 +188,6 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { RedissonSession session = (RedissonSession) createEmptySession(); session.load(attrs); session.setId(id); - session.setManager(this); - - if (session.isValid()) { - if (session.isNew()) { - session.tellNew(); - } - super.add(session); - } session.access(); session.endAccess(); @@ -249,16 +251,23 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { getEngine().getPipeline().addValve(new UpdateValve(this)); } - if (readMode == ReadMode.MEMORY) { + if (readMode == ReadMode.MEMORY || broadcastSessionEvents) { RTopic updatesTopic = getTopic(); updatesTopic.addListener(AttributeMessage.class, new MessageListener() { @Override public void onMessage(CharSequence channel, AttributeMessage msg) { try { - // TODO make it thread-safe + if (msg.getNodeId().equals(nodeId)) { + return; + } + RedissonSession session = (RedissonSession) RedissonSessionManager.super.findSession(msg.getSessionId()); - if (session != null && !msg.getNodeId().equals(nodeId)) { + if (session != null) { + if (msg instanceof SessionDestroyedMessage) { + session.expire(); + } + if (msg instanceof AttributeRemoveMessage) { for (String name : ((AttributeRemoveMessage)msg).getNames()) { session.superRemoveAttributeInternal(name, true); @@ -280,9 +289,17 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle { AttributeUpdateMessage m = (AttributeUpdateMessage)msg; session.superSetAttribute(m.getName(), m.getValue(codecToUse.getMapValueDecoder()), true); } + } else { + if (msg instanceof SessionCreatedMessage) { + Session s = findSession(msg.getSessionId()); + if (s == null) { + throw new IllegalStateException("Unable to find session: " + msg.getSessionId()); + } + } } + } catch (Exception e) { - log.error("Can't handle topic message", e); + log.error("Unable to handle topic message", e); } } }); diff --git a/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java new file mode 100644 index 000000000..04d8973db --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionCreatedMessage extends AttributeMessage { + + public SessionCreatedMessage() { + } + + public SessionCreatedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java new file mode 100644 index 000000000..4f22eaafa --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionDestroyedMessage extends AttributeMessage { + + public SessionDestroyedMessage() { + } + + public SessionDestroyedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java index 5cabce824..75ed1e751 100644 --- a/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java +++ b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -28,6 +28,8 @@ import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; import org.apache.catalina.session.ManagerBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -61,6 +63,7 @@ public class RedissonSessionManager extends ManagerBase { private UpdateMode updateMode = UpdateMode.DEFAULT; private String keyPrefix = ""; + private boolean broadcastSessionEvents = false; private final String nodeId = UUID.randomUUID().toString(); @@ -74,6 +77,14 @@ public class RedissonSessionManager extends ManagerBase { this.updateMode = UpdateMode.valueOf(updateMode); } + public boolean isBroadcastSessionEvents() { + return broadcastSessionEvents; + } + + public void setBroadcastSessionEvents(boolean replicateSessionEvents) { + this.broadcastSessionEvents = replicateSessionEvents; + } + public String getReadMode() { return readMode.toString(); } @@ -113,23 +124,22 @@ public class RedissonSessionManager extends ManagerBase { @Override public Session createSession(String sessionId) { - RedissonSession session = (RedissonSession) createEmptySession(); + Session session = super.createSession(sessionId); - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); - - if (sessionId == null) { - sessionId = generateSessionId(); + if (broadcastSessionEvents) { + getTopic().publish(new SessionCreatedMessage(getNodeId(), session.getId())); + session.addSessionListener(new SessionListener() { + @Override + public void sessionEvent(SessionEvent event) { + if (event.getType() == Session.SESSION_DESTROYED_EVENT) { + getTopic().publish(new SessionDestroyedMessage(getNodeId(), session.getId())); + } + } + }); } - - session.setManager(this); - session.setId(sessionId); - return session; } - + public RMap getMap(String sessionId) { String separator = keyPrefix == null || keyPrefix.isEmpty() ? "" : ":"; String name = keyPrefix + separator + "redisson:tomcat_session:" + sessionId; @@ -157,14 +167,6 @@ public class RedissonSessionManager extends ManagerBase { RedissonSession session = (RedissonSession) createEmptySession(); session.load(attrs); session.setId(id); - session.setManager(this); - - if (session.isValid()) { - if (session.isNew()) { - session.tellNew(); - } - super.add(session); - } session.access(); session.endAccess(); @@ -229,16 +231,23 @@ public class RedissonSessionManager extends ManagerBase { getEngine().getPipeline().addValve(new UpdateValve(this)); } - if (readMode == ReadMode.MEMORY) { + if (readMode == ReadMode.MEMORY || broadcastSessionEvents) { RTopic updatesTopic = getTopic(); updatesTopic.addListener(AttributeMessage.class, new MessageListener() { @Override public void onMessage(CharSequence channel, AttributeMessage msg) { try { - // TODO make it thread-safe + if (msg.getNodeId().equals(nodeId)) { + return; + } + RedissonSession session = (RedissonSession) RedissonSessionManager.super.findSession(msg.getSessionId()); - if (session != null && !msg.getNodeId().equals(nodeId)) { + if (session != null) { + if (msg instanceof SessionDestroyedMessage) { + session.expire(); + } + if (msg instanceof AttributeRemoveMessage) { for (String name : ((AttributeRemoveMessage)msg).getNames()) { session.superRemoveAttributeInternal(name, true); @@ -260,9 +269,17 @@ public class RedissonSessionManager extends ManagerBase { AttributeUpdateMessage m = (AttributeUpdateMessage)msg; session.superSetAttribute(m.getName(), m.getValue(codecToUse.getMapValueDecoder()), true); } + } else { + if (msg instanceof SessionCreatedMessage) { + Session s = findSession(msg.getSessionId()); + if (s == null) { + throw new IllegalStateException("Unable to find session: " + msg.getSessionId()); + } + } } + } catch (Exception e) { - log.error("Can't handle topic message", e); + log.error("Unable to handle topic message", e); } } }); diff --git a/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java new file mode 100644 index 000000000..04d8973db --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionCreatedMessage extends AttributeMessage { + + public SessionCreatedMessage() { + } + + public SessionCreatedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java new file mode 100644 index 000000000..4f22eaafa --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionDestroyedMessage extends AttributeMessage { + + public SessionDestroyedMessage() { + } + + public SessionDestroyedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java index 3c59b21f7..c1aa80630 100644 --- a/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java +++ b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java @@ -17,6 +17,35 @@ import org.redisson.config.Config; public class RedissonSessionManagerTest { + @Test + public void testHttpSessionListener() throws Exception { + TomcatServer server1 = new TomcatServer("myapp", 8080, "src/test/"); + server1.start(); + + TomcatServer server2 = new TomcatServer("myapp", 8081, "src/test/"); + server2.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + TestHttpSessionListener.CREATED_INVOCATION_COUNTER = 0; + TestHttpSessionListener.DESTROYED_INVOCATION_COUNTER = 0; + + write(executor, "test", "1234"); + + invalidate(executor); + + Thread.sleep(500); + + Assert.assertEquals(2, TestHttpSessionListener.CREATED_INVOCATION_COUNTER); + Assert.assertEquals(2, TestHttpSessionListener.DESTROYED_INVOCATION_COUNTER); + + Executor.closeIdleConnections(); + server1.stop(); + server2.stop(); + } + @Test public void testUpdateTwoServers() throws Exception { TomcatServer server1 = new TomcatServer("myapp", 8080, "src/test/"); diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestHttpSessionListener.java b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestHttpSessionListener.java new file mode 100644 index 000000000..36480899d --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestHttpSessionListener.java @@ -0,0 +1,21 @@ +package org.redisson.tomcat; + +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +public class TestHttpSessionListener implements HttpSessionListener { + + public static int CREATED_INVOCATION_COUNTER; + public static int DESTROYED_INVOCATION_COUNTER; + + @Override + public void sessionCreated(HttpSessionEvent se) { + CREATED_INVOCATION_COUNTER++; + } + + @Override + public void sessionDestroyed(HttpSessionEvent se) { + DESTROYED_INVOCATION_COUNTER++; + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml index 52b0eafd8..f2c9a7031 100644 --- a/redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml +++ b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml @@ -2,6 +2,7 @@ + configPath="${catalina.base}/src/test/webapp/WEB-INF/redisson.yaml" + broadcastSessionEvents="true"/> \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml index 4e9b56d97..c84221b8c 100644 --- a/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml +++ b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml @@ -18,5 +18,9 @@ 1 + + + org.redisson.tomcat.TestHttpSessionListener + diff --git a/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java index 000a9e6d4..efe49413f 100644 --- a/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java +++ b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -27,6 +27,8 @@ import javax.servlet.http.HttpSession; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; import org.apache.catalina.session.ManagerBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -60,6 +62,7 @@ public class RedissonSessionManager extends ManagerBase { private UpdateMode updateMode = UpdateMode.DEFAULT; private String keyPrefix = ""; + private boolean broadcastSessionEvents = false; private final String nodeId = UUID.randomUUID().toString(); @@ -73,6 +76,14 @@ public class RedissonSessionManager extends ManagerBase { this.updateMode = UpdateMode.valueOf(updateMode); } + public boolean isBroadcastSessionEvents() { + return broadcastSessionEvents; + } + + public void setBroadcastSessionEvents(boolean replicateSessionEvents) { + this.broadcastSessionEvents = replicateSessionEvents; + } + public String getReadMode() { return readMode.toString(); } @@ -112,23 +123,22 @@ public class RedissonSessionManager extends ManagerBase { @Override public Session createSession(String sessionId) { - RedissonSession session = (RedissonSession) createEmptySession(); + Session session = super.createSession(sessionId); - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60); - - if (sessionId == null) { - sessionId = generateSessionId(); + if (broadcastSessionEvents) { + getTopic().publish(new SessionCreatedMessage(getNodeId(), session.getId())); + session.addSessionListener(new SessionListener() { + @Override + public void sessionEvent(SessionEvent event) { + if (event.getType() == Session.SESSION_DESTROYED_EVENT) { + getTopic().publish(new SessionDestroyedMessage(getNodeId(), session.getId())); + } + } + }); } - - session.setManager(this); - session.setId(sessionId); - return session; } - + public RMap getMap(String sessionId) { String separator = keyPrefix == null || keyPrefix.isEmpty() ? "" : ":"; String name = keyPrefix + separator + "redisson:tomcat_session:" + sessionId; @@ -156,14 +166,6 @@ public class RedissonSessionManager extends ManagerBase { RedissonSession session = (RedissonSession) createEmptySession(); session.load(attrs); session.setId(id); - session.setManager(this); - - if (session.isValid()) { - if (session.isNew()) { - session.tellNew(); - } - super.add(session); - } session.access(); session.endAccess(); @@ -228,16 +230,23 @@ public class RedissonSessionManager extends ManagerBase { getEngine().getPipeline().addValve(new UpdateValve(this)); } - if (readMode == ReadMode.MEMORY) { + if (readMode == ReadMode.MEMORY || broadcastSessionEvents) { RTopic updatesTopic = getTopic(); updatesTopic.addListener(AttributeMessage.class, new MessageListener() { @Override public void onMessage(CharSequence channel, AttributeMessage msg) { try { - // TODO make it thread-safe + if (msg.getNodeId().equals(nodeId)) { + return; + } + RedissonSession session = (RedissonSession) RedissonSessionManager.super.findSession(msg.getSessionId()); - if (session != null && !msg.getNodeId().equals(nodeId)) { + if (session != null) { + if (msg instanceof SessionDestroyedMessage) { + session.expire(); + } + if (msg instanceof AttributeRemoveMessage) { for (String name : ((AttributeRemoveMessage)msg).getNames()) { session.superRemoveAttributeInternal(name, true); @@ -259,9 +268,17 @@ public class RedissonSessionManager extends ManagerBase { AttributeUpdateMessage m = (AttributeUpdateMessage)msg; session.superSetAttribute(m.getName(), m.getValue(codecToUse.getMapValueDecoder()), true); } + } else { + if (msg instanceof SessionCreatedMessage) { + Session s = findSession(msg.getSessionId()); + if (s == null) { + throw new IllegalStateException("Unable to find session: " + msg.getSessionId()); + } } + } + } catch (Exception e) { - log.error("Can't handle topic message", e); + log.error("Unable to handle topic message", e); } } }); diff --git a/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java new file mode 100644 index 000000000..04d8973db --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionCreatedMessage extends AttributeMessage { + + public SessionCreatedMessage() { + } + + public SessionCreatedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java new file mode 100644 index 000000000..4f22eaafa --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionDestroyedMessage extends AttributeMessage { + + public SessionDestroyedMessage() { + } + + public SessionDestroyedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/RedissonSessionManager.java b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/RedissonSessionManager.java index 000a9e6d4..efe49413f 100644 --- a/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/RedissonSessionManager.java +++ b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -27,6 +27,8 @@ import javax.servlet.http.HttpSession; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; import org.apache.catalina.session.ManagerBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -60,6 +62,7 @@ public class RedissonSessionManager extends ManagerBase { private UpdateMode updateMode = UpdateMode.DEFAULT; private String keyPrefix = ""; + private boolean broadcastSessionEvents = false; private final String nodeId = UUID.randomUUID().toString(); @@ -73,6 +76,14 @@ public class RedissonSessionManager extends ManagerBase { this.updateMode = UpdateMode.valueOf(updateMode); } + public boolean isBroadcastSessionEvents() { + return broadcastSessionEvents; + } + + public void setBroadcastSessionEvents(boolean replicateSessionEvents) { + this.broadcastSessionEvents = replicateSessionEvents; + } + public String getReadMode() { return readMode.toString(); } @@ -112,23 +123,22 @@ public class RedissonSessionManager extends ManagerBase { @Override public Session createSession(String sessionId) { - RedissonSession session = (RedissonSession) createEmptySession(); + Session session = super.createSession(sessionId); - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60); - - if (sessionId == null) { - sessionId = generateSessionId(); + if (broadcastSessionEvents) { + getTopic().publish(new SessionCreatedMessage(getNodeId(), session.getId())); + session.addSessionListener(new SessionListener() { + @Override + public void sessionEvent(SessionEvent event) { + if (event.getType() == Session.SESSION_DESTROYED_EVENT) { + getTopic().publish(new SessionDestroyedMessage(getNodeId(), session.getId())); + } + } + }); } - - session.setManager(this); - session.setId(sessionId); - return session; } - + public RMap getMap(String sessionId) { String separator = keyPrefix == null || keyPrefix.isEmpty() ? "" : ":"; String name = keyPrefix + separator + "redisson:tomcat_session:" + sessionId; @@ -156,14 +166,6 @@ public class RedissonSessionManager extends ManagerBase { RedissonSession session = (RedissonSession) createEmptySession(); session.load(attrs); session.setId(id); - session.setManager(this); - - if (session.isValid()) { - if (session.isNew()) { - session.tellNew(); - } - super.add(session); - } session.access(); session.endAccess(); @@ -228,16 +230,23 @@ public class RedissonSessionManager extends ManagerBase { getEngine().getPipeline().addValve(new UpdateValve(this)); } - if (readMode == ReadMode.MEMORY) { + if (readMode == ReadMode.MEMORY || broadcastSessionEvents) { RTopic updatesTopic = getTopic(); updatesTopic.addListener(AttributeMessage.class, new MessageListener() { @Override public void onMessage(CharSequence channel, AttributeMessage msg) { try { - // TODO make it thread-safe + if (msg.getNodeId().equals(nodeId)) { + return; + } + RedissonSession session = (RedissonSession) RedissonSessionManager.super.findSession(msg.getSessionId()); - if (session != null && !msg.getNodeId().equals(nodeId)) { + if (session != null) { + if (msg instanceof SessionDestroyedMessage) { + session.expire(); + } + if (msg instanceof AttributeRemoveMessage) { for (String name : ((AttributeRemoveMessage)msg).getNames()) { session.superRemoveAttributeInternal(name, true); @@ -259,9 +268,17 @@ public class RedissonSessionManager extends ManagerBase { AttributeUpdateMessage m = (AttributeUpdateMessage)msg; session.superSetAttribute(m.getName(), m.getValue(codecToUse.getMapValueDecoder()), true); } + } else { + if (msg instanceof SessionCreatedMessage) { + Session s = findSession(msg.getSessionId()); + if (s == null) { + throw new IllegalStateException("Unable to find session: " + msg.getSessionId()); + } } + } + } catch (Exception e) { - log.error("Can't handle topic message", e); + log.error("Unable to handle topic message", e); } } }); diff --git a/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java new file mode 100644 index 000000000..04d8973db --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionCreatedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionCreatedMessage extends AttributeMessage { + + public SessionCreatedMessage() { + } + + public SessionCreatedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java new file mode 100644 index 000000000..4f22eaafa --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-9/src/main/java/org/redisson/tomcat/SessionDestroyedMessage.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2013-2019 Nikita Koksharov + * + * 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.redisson.tomcat; + +/** + * + * @author Nikita Koksharov + * + */ +public class SessionDestroyedMessage extends AttributeMessage { + + public SessionDestroyedMessage() { + } + + public SessionDestroyedMessage(String nodeId, String sessionId) { + super(nodeId, sessionId); + } + +}