From c378299009718b1146eec2afa47b5c34eec23c8e Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 17 Nov 2016 17:21:57 +0300 Subject: [PATCH] Tomcat session manager implemented. #590 --- pom.xml | 1 + redisson-tomcat/pom.xml | 61 ++++++ redisson-tomcat/redisson-tomcat-6/pom.xml | 64 ++++++ .../org/redisson/tomcat/RedissonSession.java | 172 ++++++++++++++++ .../tomcat/RedissonSessionManager.java | 179 +++++++++++++++++ .../tomcat/RedissonSessionManagerTest.java | 153 +++++++++++++++ .../java/org/redisson/tomcat/TestServlet.java | 94 +++++++++ .../org/redisson/tomcat/TomcatServer.java | 109 +++++++++++ .../src/test/webapp/META-INF/context.xml | 7 + .../src/test/webapp/WEB-INF/redisson.yaml | 3 + .../src/test/webapp/WEB-INF/web.xml | 22 +++ redisson-tomcat/redisson-tomcat-7/pom.xml | 82 ++++++++ .../org/redisson/tomcat/RedissonSession.java | 172 ++++++++++++++++ .../tomcat/RedissonSessionManager.java | 185 ++++++++++++++++++ .../tomcat/RedissonSessionManagerTest.java | 152 ++++++++++++++ .../java/org/redisson/tomcat/TestServlet.java | 94 +++++++++ .../org/redisson/tomcat/TomcatServer.java | 64 ++++++ .../src/test/webapp/META-INF/context.xml | 7 + .../src/test/webapp/WEB-INF/redisson.yaml | 3 + .../src/test/webapp/WEB-INF/web.xml | 22 +++ redisson-tomcat/redisson-tomcat-8/pom.xml | 81 ++++++++ .../org/redisson/tomcat/RedissonSession.java | 172 ++++++++++++++++ .../tomcat/RedissonSessionManager.java | 185 ++++++++++++++++++ .../tomcat/RedissonSessionManagerTest.java | 152 ++++++++++++++ .../java/org/redisson/tomcat/TestServlet.java | 94 +++++++++ .../org/redisson/tomcat/TomcatServer.java | 64 ++++++ .../src/test/webapp/META-INF/context.xml | 7 + .../src/test/webapp/WEB-INF/redisson.yaml | 3 + .../src/test/webapp/WEB-INF/web.xml | 22 +++ redisson/header.txt | 13 -- 30 files changed, 2426 insertions(+), 13 deletions(-) create mode 100644 redisson-tomcat/pom.xml create mode 100644 redisson-tomcat/redisson-tomcat-6/pom.xml create mode 100644 redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSession.java create mode 100644 redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TestServlet.java create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TomcatServer.java create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/webapp/META-INF/context.xml create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/redisson.yaml create mode 100644 redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/web.xml create mode 100644 redisson-tomcat/redisson-tomcat-7/pom.xml create mode 100644 redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSession.java create mode 100644 redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestServlet.java create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TomcatServer.java create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/redisson.yaml create mode 100644 redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml create mode 100644 redisson-tomcat/redisson-tomcat-8/pom.xml create mode 100644 redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSession.java create mode 100644 redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TestServlet.java create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TomcatServer.java create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/webapp/META-INF/context.xml create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/redisson.yaml create mode 100644 redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/web.xml delete mode 100644 redisson/header.txt diff --git a/pom.xml b/pom.xml index 5c19e6cd0..acf433059 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ redisson redisson-all + redisson-tomcat diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml new file mode 100644 index 000000000..223bb4b7c --- /dev/null +++ b/redisson-tomcat/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + + + org.redisson + redisson-parent + 2.6.1-SNAPSHOT + ../ + + + redisson-tomcat + pom + + Redisson/Tomcat + + + redisson-tomcat-6 + redisson-tomcat-7 + redisson-tomcat-8 + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + + attach-javadocs + + jar + + + + + + + + + + org.redisson + redisson + ${project.version} + + + + org.apache.httpcomponents + fluent-hc + 4.5.2 + test + + + junit + junit + 4.12 + test + + + + diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml new file mode 100644 index 000000000..7bfc849c7 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -0,0 +1,64 @@ + + 4.0.0 + + + org.redisson + redisson-tomcat + 2.6.1-SNAPSHOT + ../ + + + redisson-tomcat-6 + jar + + Redisson/Tomcat-6 + + + + org.apache.tomcat + catalina + 6.0.48 + provided + + + + + + + com.mycila + license-maven-plugin + 3.0 + + ${basedir} +
${basedir}/../../header.txt
+ false + true + false + + src/main/java/org/redisson/ + + + target/** + + true + + JAVADOC_STYLE + + true + true + UTF-8 +
+ + + + check + + + +
+ +
+
+ + +
diff --git a/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSession.java b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSession.java new file mode 100644 index 000000000..2f2e934b5 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSession.java @@ -0,0 +1,172 @@ +/** + * Copyright 2016 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; + +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.catalina.session.StandardSession; +import org.redisson.api.RMap; + +/** + * Redisson Session object for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSession extends StandardSession { + + private final RedissonSessionManager redissonManager; + private RMap map; + + public RedissonSession(RedissonSessionManager manager) { + super(manager); + this.redissonManager = manager; + } + + private static final long serialVersionUID = -2518607181636076487L; + + @Override + public void setId(String id, boolean notify) { + super.setId(id, notify); + map = redissonManager.getMap(id); + } + + @Override + public void setCreationTime(long time) { + super.setCreationTime(time); + + if (map != null) { + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + } + } + + @Override + public void access() { + super.access(); + + if (map != null) { + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + if (getMaxInactiveInterval() >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setMaxInactiveInterval(int interval) { + super.setMaxInactiveInterval(interval); + + if (map != null) { + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + if (maxInactiveInterval >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setValid(boolean isValid) { + super.setValid(isValid); + + if (map != null) { + map.fastPut("session:isValid", isValid); + } + } + + @Override + public void setNew(boolean isNew) { + super.setNew(isNew); + + if (map != null) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void endAccess() { + boolean oldValue = isNew; + super.endAccess(); + + if (isNew != oldValue) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void setAttribute(String name, Object value, boolean notify) { + super.setAttribute(name, value, notify); + + if (map != null && value != null) { + map.fastPut(name, value); + } + } + + @Override + protected void removeAttributeInternal(String name, boolean notify) { + super.removeAttributeInternal(name, notify); + + if (getId() != null) { + RMap map = redissonManager.getMap(getId()); + map.fastRemove(name); + } + } + + public void save() { + RMap map = redissonManager.getMap(getId()); + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + map.fastPut("session:isValid", isValid); + map.fastPut("session:isNew", isNew); + + for (Entry entry : attributes.entrySet()) { + map.fastPut(entry.getKey(), entry.getValue()); + } + } + + public void load() { + RMap map = redissonManager.getMap(getId()); + if (!map.isExists()) { + return; + } + + Set> entrySet = map.readAllEntrySet(); + for (Entry entry : entrySet) { + if ("session:creationTime".equals(entry.getKey())) { + creationTime = (Long) entry.getValue(); + } else if ("session:lastAccessedTime".equals(entry.getKey())) { + lastAccessedTime = (Long) entry.getValue(); + } else if ("session:thisAccessedTime".equals(entry.getKey())) { + thisAccessedTime = (Long) entry.getValue(); + } else if ("session:maxInactiveInterval".equals(entry.getKey())) { + maxInactiveInterval = (Integer) entry.getValue(); + } else if ("session:isValid".equals(entry.getKey())) { + isValid = (Boolean) entry.getValue(); + } else if ("session:isNew".equals(entry.getKey())) { + isNew = (Boolean) entry.getValue(); + } else { + setAttribute(entry.getKey(), entry.getValue(), false); + } + } + } + +} 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 new file mode 100644 index 000000000..6399320c0 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -0,0 +1,179 @@ +/** + * Copyright 2016 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; + +import java.io.File; +import java.io.IOException; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Session; +import org.apache.catalina.session.ManagerBase; +import org.apache.catalina.util.LifecycleSupport; +import org.redisson.Redisson; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; + +/** + * Redisson Session Manager for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSessionManager extends ManagerBase implements Lifecycle { + + private final Log log = LogFactory.getLog(RedissonSessionManager.class); + + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + private RedissonClient redisson; + private String configPath; + + public void setConfigPath(String configPath) { + this.configPath = configPath; + } + + public String getConfigPath() { + return configPath; + } + + @Override + public int getRejectedSessions() { + return 0; + } + + @Override + public void load() throws ClassNotFoundException, IOException { + } + + @Override + public void setRejectedSessions(int sessions) { + } + + @Override + public void unload() throws IOException { + } + + @Override + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + @Override + public LifecycleListener[] findLifecycleListeners() { + return lifecycle.findLifecycleListeners(); + } + + @Override + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + @Override + public Session createSession(String sessionId) { + RedissonSession session = (RedissonSession) createEmptySession(); + + session.setNew(true); + session.setValid(true); + session.setCreationTime(System.currentTimeMillis()); + session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); + + if (sessionId == null) { + sessionId = generateSessionId(); + } + + session.setId(sessionId); + session.save(); + + return session; + } + + public RMap getMap(String sessionId) { + return redisson.getMap("redisson_tomcat_session:" + sessionId); + } + + @Override + public Session findSession(String id) throws IOException { + Session result = super.findSession(id); + if (result == null && id != null) { + RedissonSession session = (RedissonSession) createEmptySession(); + session.setId(id); + session.load(); + return session; + } + + return result; + } + + @Override + public Session createEmptySession() { + return new RedissonSession(this); + } + + @Override + public void remove(Session session) { + super.remove(session); + + getMap(session.getId()).delete(); + } + + public RedissonClient getRedisson() { + return redisson; + } + + @Override + public void start() throws LifecycleException { + Config config = null; + try { + config = Config.fromJSON(new File(configPath)); + } catch (IOException e) { + // trying next format + try { + config = Config.fromYAML(new File(configPath)); + } catch (IOException e1) { + log.error("Can't parse json config " + configPath, e); + throw new LifecycleException("Can't parse yaml config " + configPath, e1); + } + } + + try { + redisson = Redisson.create(config); + } catch (Exception e) { + throw new LifecycleException(e); + } + + lifecycle.fireLifecycleEvent(START_EVENT, null); + } + + @Override + public void stop() throws LifecycleException { + try { + if (redisson != null) { + redisson.shutdown(); + } + } catch (Exception e) { + throw new LifecycleException(e); + } + + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java new file mode 100644 index 000000000..dd8703be4 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java @@ -0,0 +1,153 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import org.apache.catalina.LifecycleException; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.fluent.Executor; +import org.apache.http.client.fluent.Request; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; +import org.junit.Assert; +import org.junit.Test; + +public class RedissonSessionManagerTest { + + @Test + public void testSwitchServer() throws LifecycleException, InterruptedException, ClientProtocolException, IOException { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + + Executor.closeIdleConnections(); + server.stop(); + + server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testWriteReadRemove() throws LifecycleException, InterruptedException, ClientProtocolException, IOException { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1234"); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testRecreate() throws LifecycleException, InterruptedException, ClientProtocolException, IOException { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + recreate(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testUpdate() throws LifecycleException, InterruptedException, ClientProtocolException, IOException { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + read(executor, "test", "1"); + write(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testInvalidate() throws LifecycleException, InterruptedException, ClientProtocolException, IOException { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + invalidate(executor); + + Executor.closeIdleConnections(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/write?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void read(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/read?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void remove(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/remove?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void invalidate(Executor executor) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/invalidate"; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void recreate(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/recreate?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TestServlet.java b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TestServlet.java new file mode 100644 index 000000000..1c68da965 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TestServlet.java @@ -0,0 +1,94 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class TestServlet extends HttpServlet { + + private static final long serialVersionUID = 1243830648280853203L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(); + + if (req.getPathInfo().equals("/write")) { + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/read")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + Object attr = session.getAttribute(key); + resp.getWriter().print(attr); + } else if (req.getPathInfo().equals("/remove")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + session.removeAttribute(key); + resp.getWriter().print(String.valueOf(session.getAttribute(key))); + } else if (req.getPathInfo().equals("/invalidate")) { + session.invalidate(); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/recreate")) { + session.invalidate(); + + session = req.getSession(); + + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } + } + +} diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TomcatServer.java b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TomcatServer.java new file mode 100644 index 000000000..62c0525fb --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/java/org/redisson/tomcat/TomcatServer.java @@ -0,0 +1,109 @@ +package org.redisson.tomcat; + +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.startup.Embedded; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TomcatServer { + + private Embedded server; + private int port; + private boolean isRunning; + + private static final Logger LOG = LoggerFactory.getLogger(TomcatServer.class); + private static final boolean isInfo = LOG.isInfoEnabled(); + + + /** + * Create a new Tomcat embedded server instance. Setup looks like: + *

+     *    
+     *        
+     *        
+     *                
+     *            
+     *        
+     *    
+     *
+ * & will be created automcatically. We need to hook the remaining to an {@link Embedded} instnace + * @param contextPath Context path for the application + * @param port Port number to be used for the embedded Tomcat server + * @param appBase Path to the Application files (for Maven based web apps, in general: /src/main/) + * @param shutdownHook If true, registers a server' shutdown hook with JVM. This is useful to shutdown the server + * in erroneous cases. + * @throws Exception + */ + public TomcatServer(String contextPath, int port, String appBase) { + if(contextPath == null || appBase == null || appBase.length() == 0) { + throw new IllegalArgumentException("Context path or appbase should not be null"); + } + if(!contextPath.startsWith("/")) { + contextPath = "/" + contextPath; + } + + this.port = port; + + server = new Embedded(); + server.setName("TomcatEmbeddedServer"); + + Host localHost = server.createHost("localhost", appBase); + localHost.setAutoDeploy(false); + + StandardContext rootContext = (StandardContext) server.createContext(contextPath, "webapp"); + rootContext.setDefaultWebXml("web.xml"); + localHost.addChild(rootContext); + + Engine engine = server.createEngine(); + engine.setDefaultHost(localHost.getName()); + engine.setName("TomcatEngine"); + engine.addChild(localHost); + + server.addEngine(engine); + + Connector connector = server.createConnector(localHost.getName(), port, false); + server.addConnector(connector); + + } + + /** + * Start the tomcat embedded server + */ + public void start() throws LifecycleException { + if(isRunning) { + LOG.warn("Tomcat server is already running @ port={}; ignoring the start", port); + return; + } + + if(isInfo) LOG.info("Starting the Tomcat server @ port={}", port); + + server.setAwait(true); + server.start(); + isRunning = true; + } + + /** + * Stop the tomcat embedded server + */ + public void stop() throws LifecycleException { + if(!isRunning) { + LOG.warn("Tomcat server is not running @ port={}", port); + return; + } + + if(isInfo) LOG.info("Stopping the Tomcat server"); + + server.stop(); + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + +} \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/webapp/META-INF/context.xml b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/META-INF/context.xml new file mode 100644 index 000000000..52b0eafd8 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/META-INF/context.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/redisson.yaml b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/redisson.yaml new file mode 100644 index 000000000..8f5de4111 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/redisson.yaml @@ -0,0 +1,3 @@ +singleServerConfig: + address: + - "//127.0.0.1:6379" \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/web.xml b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..5940ccb8a --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-6/src/test/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + testServlet + org.redisson.tomcat.TestServlet + 1 + + + + testServlet + /* + + + + 30 + + + diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml new file mode 100644 index 000000000..0cc485305 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -0,0 +1,82 @@ + + 4.0.0 + + + org.redisson + redisson-tomcat + 2.6.1-SNAPSHOT + ../ + + + redisson-tomcat-7 + jar + + Redisson/Tomcat-7 + + + + org.apache.tomcat.embed + tomcat-embed-core + 7.0.73 + provided + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + 7.0.73 + provided + + + org.apache.tomcat.embed + tomcat-embed-jasper + 7.0.73 + provided + + + org.apache.tomcat + tomcat-jasper + 7.0.73 + provided + + + + + + + com.mycila + license-maven-plugin + 3.0 + + ${basedir} +
${basedir}/../../header.txt
+ false + true + false + + src/main/java/org/redisson/ + + + target/** + + true + + JAVADOC_STYLE + + true + true + UTF-8 +
+ + + + check + + + +
+ +
+
+ + +
diff --git a/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSession.java b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSession.java new file mode 100644 index 000000000..2f2e934b5 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSession.java @@ -0,0 +1,172 @@ +/** + * Copyright 2016 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; + +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.catalina.session.StandardSession; +import org.redisson.api.RMap; + +/** + * Redisson Session object for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSession extends StandardSession { + + private final RedissonSessionManager redissonManager; + private RMap map; + + public RedissonSession(RedissonSessionManager manager) { + super(manager); + this.redissonManager = manager; + } + + private static final long serialVersionUID = -2518607181636076487L; + + @Override + public void setId(String id, boolean notify) { + super.setId(id, notify); + map = redissonManager.getMap(id); + } + + @Override + public void setCreationTime(long time) { + super.setCreationTime(time); + + if (map != null) { + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + } + } + + @Override + public void access() { + super.access(); + + if (map != null) { + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + if (getMaxInactiveInterval() >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setMaxInactiveInterval(int interval) { + super.setMaxInactiveInterval(interval); + + if (map != null) { + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + if (maxInactiveInterval >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setValid(boolean isValid) { + super.setValid(isValid); + + if (map != null) { + map.fastPut("session:isValid", isValid); + } + } + + @Override + public void setNew(boolean isNew) { + super.setNew(isNew); + + if (map != null) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void endAccess() { + boolean oldValue = isNew; + super.endAccess(); + + if (isNew != oldValue) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void setAttribute(String name, Object value, boolean notify) { + super.setAttribute(name, value, notify); + + if (map != null && value != null) { + map.fastPut(name, value); + } + } + + @Override + protected void removeAttributeInternal(String name, boolean notify) { + super.removeAttributeInternal(name, notify); + + if (getId() != null) { + RMap map = redissonManager.getMap(getId()); + map.fastRemove(name); + } + } + + public void save() { + RMap map = redissonManager.getMap(getId()); + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + map.fastPut("session:isValid", isValid); + map.fastPut("session:isNew", isNew); + + for (Entry entry : attributes.entrySet()) { + map.fastPut(entry.getKey(), entry.getValue()); + } + } + + public void load() { + RMap map = redissonManager.getMap(getId()); + if (!map.isExists()) { + return; + } + + Set> entrySet = map.readAllEntrySet(); + for (Entry entry : entrySet) { + if ("session:creationTime".equals(entry.getKey())) { + creationTime = (Long) entry.getValue(); + } else if ("session:lastAccessedTime".equals(entry.getKey())) { + lastAccessedTime = (Long) entry.getValue(); + } else if ("session:thisAccessedTime".equals(entry.getKey())) { + thisAccessedTime = (Long) entry.getValue(); + } else if ("session:maxInactiveInterval".equals(entry.getKey())) { + maxInactiveInterval = (Integer) entry.getValue(); + } else if ("session:isValid".equals(entry.getKey())) { + isValid = (Boolean) entry.getValue(); + } else if ("session:isNew".equals(entry.getKey())) { + isNew = (Boolean) entry.getValue(); + } else { + setAttribute(entry.getKey(), entry.getValue(), false); + } + } + } + +} 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 new file mode 100644 index 000000000..87d41f81a --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -0,0 +1,185 @@ +/** + * Copyright 2016 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; + +import java.io.File; +import java.io.IOException; + +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.LifecycleState; +import org.apache.catalina.Session; +import org.apache.catalina.session.ManagerBase; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.redisson.Redisson; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; + +/** + * Redisson Session Manager for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSessionManager extends ManagerBase implements Lifecycle { + + private final Log log = LogFactory.getLog(RedissonSessionManager.class); + + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + private RedissonClient redisson; + private String configPath; + + public void setConfigPath(String configPath) { + this.configPath = configPath; + } + + public String getConfigPath() { + return configPath; + } + + @Override + public String getName() { + return RedissonSessionManager.class.getSimpleName(); + } + + @Override + public int getRejectedSessions() { + return 0; + } + + @Override + public void load() throws ClassNotFoundException, IOException { + } + + @Override + public void unload() throws IOException { + } + + @Override + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + @Override + public LifecycleListener[] findLifecycleListeners() { + return lifecycle.findLifecycleListeners(); + } + + @Override + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + @Override + public Session createSession(String sessionId) { + RedissonSession session = (RedissonSession) createEmptySession(); + + session.setNew(true); + session.setValid(true); + session.setCreationTime(System.currentTimeMillis()); + session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); + + if (sessionId == null) { + sessionId = generateSessionId(); + } + + session.setId(sessionId); + session.save(); + + return session; + } + + public RMap getMap(String sessionId) { + return redisson.getMap("redisson_tomcat_session:" + sessionId); + } + + @Override + public Session findSession(String id) throws IOException { + Session result = super.findSession(id); + if (result == null && id != null) { + RedissonSession session = (RedissonSession) createEmptySession(); + session.setId(id); + session.load(); + return session; + } + + return result; + } + + @Override + public Session createEmptySession() { + return new RedissonSession(this); + } + + @Override + public void remove(Session session) { + super.remove(session); + + getMap(session.getId()).delete(); + } + + public RedissonClient getRedisson() { + return redisson; + } + + @Override + protected void startInternal() throws LifecycleException { + super.startInternal(); + Config config = null; + try { + config = Config.fromJSON(new File(configPath)); + } catch (IOException e) { + // trying next format + try { + config = Config.fromYAML(new File(configPath)); + } catch (IOException e1) { + log.error("Can't parse json config " + configPath, e); + throw new LifecycleException("Can't parse yaml config " + configPath, e1); + } + } + + try { + redisson = Redisson.create(config); + } catch (Exception e) { + throw new LifecycleException(e); + } + + setState(LifecycleState.STARTING); + } + + @Override + protected void stopInternal() throws LifecycleException { + super.stopInternal(); + + setState(LifecycleState.STOPPING); + + try { + if (redisson != null) { + redisson.shutdown(); + } + } catch (Exception e) { + throw new LifecycleException(e); + } + + } + +} 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 new file mode 100644 index 000000000..2d260c587 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java @@ -0,0 +1,152 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.fluent.Executor; +import org.apache.http.client.fluent.Request; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; +import org.junit.Assert; +import org.junit.Test; + +public class RedissonSessionManagerTest { + + @Test + public void testSwitchServer() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + + Executor.closeIdleConnections(); + server.stop(); + + server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testWriteReadRemove() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1234"); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testRecreate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + recreate(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testUpdate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + read(executor, "test", "1"); + write(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testInvalidate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + invalidate(executor); + + Executor.closeIdleConnections(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/write?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void read(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/read?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void remove(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/remove?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void invalidate(Executor executor) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/invalidate"; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void recreate(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/recreate?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestServlet.java b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestServlet.java new file mode 100644 index 000000000..1c68da965 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TestServlet.java @@ -0,0 +1,94 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class TestServlet extends HttpServlet { + + private static final long serialVersionUID = 1243830648280853203L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(); + + if (req.getPathInfo().equals("/write")) { + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/read")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + Object attr = session.getAttribute(key); + resp.getWriter().print(attr); + } else if (req.getPathInfo().equals("/remove")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + session.removeAttribute(key); + resp.getWriter().print(String.valueOf(session.getAttribute(key))); + } else if (req.getPathInfo().equals("/invalidate")) { + session.invalidate(); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/recreate")) { + session.invalidate(); + + session = req.getSession(); + + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } + } + +} diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TomcatServer.java b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TomcatServer.java new file mode 100644 index 000000000..16c6a25f9 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/java/org/redisson/tomcat/TomcatServer.java @@ -0,0 +1,64 @@ +package org.redisson.tomcat; + +import java.net.MalformedURLException; + +import javax.servlet.ServletException; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TomcatServer { + + private Tomcat tomcat = new Tomcat(); + private int port; + private boolean isRunning; + + private static final Logger LOG = LoggerFactory.getLogger(TomcatServer.class); + private static final boolean isInfo = LOG.isInfoEnabled(); + + public TomcatServer(String contextPath, int port, String appBase) throws MalformedURLException, ServletException { + if(contextPath == null || appBase == null || appBase.length() == 0) { + throw new IllegalArgumentException("Context path or appbase should not be null"); + } + if(!contextPath.startsWith("/")) { + contextPath = "/" + contextPath; + } + + tomcat.setBaseDir("."); // location where temp dir is created + tomcat.setPort(port); + tomcat.getHost().setAppBase("."); + + tomcat.addWebapp(contextPath, appBase + "webapp"); + } + + /** + * Start the tomcat embedded server + */ + public void start() throws LifecycleException { + tomcat.start(); + isRunning = true; + } + + /** + * Stop the tomcat embedded server + */ + public void stop() throws LifecycleException { + if(!isRunning) { + LOG.warn("Tomcat server is not running @ port={}", port); + return; + } + + if(isInfo) LOG.info("Stopping the Tomcat server"); + + tomcat.stop(); + tomcat.destroy(); + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + +} \ No newline at end of file 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 new file mode 100644 index 000000000..52b0eafd8 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/META-INF/context.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/redisson.yaml b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/redisson.yaml new file mode 100644 index 000000000..8f5de4111 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/redisson.yaml @@ -0,0 +1,3 @@ +singleServerConfig: + address: + - "//127.0.0.1:6379" \ 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 new file mode 100644 index 000000000..5940ccb8a --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-7/src/test/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + testServlet + org.redisson.tomcat.TestServlet + 1 + + + + testServlet + /* + + + + 30 + + + diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml new file mode 100644 index 000000000..c6853a9db --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + + org.redisson + redisson-tomcat + 2.6.1-SNAPSHOT + ../ + + + redisson-tomcat-8 + jar + + Redisson/Tomcat-8 + + + + org.apache.tomcat.embed + tomcat-embed-core + 8.0.39 + provided + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + 8.0.39 + provided + + + org.apache.tomcat.embed + tomcat-embed-jasper + 8.0.39 + provided + + + org.apache.tomcat + tomcat-jasper + 8.0.39 + provided + + + + + + + com.mycila + license-maven-plugin + 3.0 + + ${basedir} +
${basedir}/../../header.txt
+ false + true + false + + src/main/java/org/redisson/ + + + target/** + + true + + JAVADOC_STYLE + + true + true + UTF-8 +
+ + + + check + + + +
+ +
+
+ +
diff --git a/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSession.java b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSession.java new file mode 100644 index 000000000..2f2e934b5 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSession.java @@ -0,0 +1,172 @@ +/** + * Copyright 2016 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; + +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.catalina.session.StandardSession; +import org.redisson.api.RMap; + +/** + * Redisson Session object for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSession extends StandardSession { + + private final RedissonSessionManager redissonManager; + private RMap map; + + public RedissonSession(RedissonSessionManager manager) { + super(manager); + this.redissonManager = manager; + } + + private static final long serialVersionUID = -2518607181636076487L; + + @Override + public void setId(String id, boolean notify) { + super.setId(id, notify); + map = redissonManager.getMap(id); + } + + @Override + public void setCreationTime(long time) { + super.setCreationTime(time); + + if (map != null) { + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + } + } + + @Override + public void access() { + super.access(); + + if (map != null) { + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + if (getMaxInactiveInterval() >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setMaxInactiveInterval(int interval) { + super.setMaxInactiveInterval(interval); + + if (map != null) { + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + if (maxInactiveInterval >= 0) { + map.expire(getMaxInactiveInterval(), TimeUnit.SECONDS); + } + } + } + + @Override + public void setValid(boolean isValid) { + super.setValid(isValid); + + if (map != null) { + map.fastPut("session:isValid", isValid); + } + } + + @Override + public void setNew(boolean isNew) { + super.setNew(isNew); + + if (map != null) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void endAccess() { + boolean oldValue = isNew; + super.endAccess(); + + if (isNew != oldValue) { + map.fastPut("session:isNew", isNew); + } + } + + @Override + public void setAttribute(String name, Object value, boolean notify) { + super.setAttribute(name, value, notify); + + if (map != null && value != null) { + map.fastPut(name, value); + } + } + + @Override + protected void removeAttributeInternal(String name, boolean notify) { + super.removeAttributeInternal(name, notify); + + if (getId() != null) { + RMap map = redissonManager.getMap(getId()); + map.fastRemove(name); + } + } + + public void save() { + RMap map = redissonManager.getMap(getId()); + map.fastPut("session:creationTime", creationTime); + map.fastPut("session:lastAccessedTime", lastAccessedTime); + map.fastPut("session:thisAccessedTime", thisAccessedTime); + map.fastPut("session:maxInactiveInterval", maxInactiveInterval); + map.fastPut("session:isValid", isValid); + map.fastPut("session:isNew", isNew); + + for (Entry entry : attributes.entrySet()) { + map.fastPut(entry.getKey(), entry.getValue()); + } + } + + public void load() { + RMap map = redissonManager.getMap(getId()); + if (!map.isExists()) { + return; + } + + Set> entrySet = map.readAllEntrySet(); + for (Entry entry : entrySet) { + if ("session:creationTime".equals(entry.getKey())) { + creationTime = (Long) entry.getValue(); + } else if ("session:lastAccessedTime".equals(entry.getKey())) { + lastAccessedTime = (Long) entry.getValue(); + } else if ("session:thisAccessedTime".equals(entry.getKey())) { + thisAccessedTime = (Long) entry.getValue(); + } else if ("session:maxInactiveInterval".equals(entry.getKey())) { + maxInactiveInterval = (Integer) entry.getValue(); + } else if ("session:isValid".equals(entry.getKey())) { + isValid = (Boolean) entry.getValue(); + } else if ("session:isNew".equals(entry.getKey())) { + isNew = (Boolean) entry.getValue(); + } else { + setAttribute(entry.getKey(), entry.getValue(), false); + } + } + } + +} 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 new file mode 100644 index 000000000..87d41f81a --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/main/java/org/redisson/tomcat/RedissonSessionManager.java @@ -0,0 +1,185 @@ +/** + * Copyright 2016 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; + +import java.io.File; +import java.io.IOException; + +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.LifecycleState; +import org.apache.catalina.Session; +import org.apache.catalina.session.ManagerBase; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.redisson.Redisson; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; + +/** + * Redisson Session Manager for Apache Tomcat + * + * @author Nikita Koksharov + * + */ +public class RedissonSessionManager extends ManagerBase implements Lifecycle { + + private final Log log = LogFactory.getLog(RedissonSessionManager.class); + + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + private RedissonClient redisson; + private String configPath; + + public void setConfigPath(String configPath) { + this.configPath = configPath; + } + + public String getConfigPath() { + return configPath; + } + + @Override + public String getName() { + return RedissonSessionManager.class.getSimpleName(); + } + + @Override + public int getRejectedSessions() { + return 0; + } + + @Override + public void load() throws ClassNotFoundException, IOException { + } + + @Override + public void unload() throws IOException { + } + + @Override + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + @Override + public LifecycleListener[] findLifecycleListeners() { + return lifecycle.findLifecycleListeners(); + } + + @Override + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + @Override + public Session createSession(String sessionId) { + RedissonSession session = (RedissonSession) createEmptySession(); + + session.setNew(true); + session.setValid(true); + session.setCreationTime(System.currentTimeMillis()); + session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); + + if (sessionId == null) { + sessionId = generateSessionId(); + } + + session.setId(sessionId); + session.save(); + + return session; + } + + public RMap getMap(String sessionId) { + return redisson.getMap("redisson_tomcat_session:" + sessionId); + } + + @Override + public Session findSession(String id) throws IOException { + Session result = super.findSession(id); + if (result == null && id != null) { + RedissonSession session = (RedissonSession) createEmptySession(); + session.setId(id); + session.load(); + return session; + } + + return result; + } + + @Override + public Session createEmptySession() { + return new RedissonSession(this); + } + + @Override + public void remove(Session session) { + super.remove(session); + + getMap(session.getId()).delete(); + } + + public RedissonClient getRedisson() { + return redisson; + } + + @Override + protected void startInternal() throws LifecycleException { + super.startInternal(); + Config config = null; + try { + config = Config.fromJSON(new File(configPath)); + } catch (IOException e) { + // trying next format + try { + config = Config.fromYAML(new File(configPath)); + } catch (IOException e1) { + log.error("Can't parse json config " + configPath, e); + throw new LifecycleException("Can't parse yaml config " + configPath, e1); + } + } + + try { + redisson = Redisson.create(config); + } catch (Exception e) { + throw new LifecycleException(e); + } + + setState(LifecycleState.STARTING); + } + + @Override + protected void stopInternal() throws LifecycleException { + super.stopInternal(); + + setState(LifecycleState.STOPPING); + + try { + if (redisson != null) { + redisson.shutdown(); + } + } catch (Exception e) { + throw new LifecycleException(e); + } + + } + +} diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java new file mode 100644 index 000000000..2d260c587 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/RedissonSessionManagerTest.java @@ -0,0 +1,152 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.fluent.Executor; +import org.apache.http.client.fluent.Request; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; +import org.junit.Assert; +import org.junit.Test; + +public class RedissonSessionManagerTest { + + @Test + public void testSwitchServer() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + + Executor.closeIdleConnections(); + server.stop(); + + server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testWriteReadRemove() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1234"); + read(executor, "test", "1234"); + remove(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testRecreate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + recreate(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + @Test + public void testUpdate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + + write(executor, "test", "1"); + read(executor, "test", "1"); + write(executor, "test", "2"); + read(executor, "test", "2"); + + Executor.closeIdleConnections(); + server.stop(); + } + + + @Test + public void testInvalidate() throws Exception { + // start the server at http://localhost:8080/myapp + TomcatServer server = new TomcatServer("myapp", 8080, "src/test/"); + server.start(); + + Executor executor = Executor.newInstance(); + BasicCookieStore cookieStore = new BasicCookieStore(); + executor.use(cookieStore); + + write(executor, "test", "1234"); + Cookie cookie = cookieStore.getCookies().get(0); + invalidate(executor); + + Executor.closeIdleConnections(); + + executor = Executor.newInstance(); + cookieStore = new BasicCookieStore(); + cookieStore.addCookie(cookie); + executor.use(cookieStore); + read(executor, "test", "null"); + + Executor.closeIdleConnections(); + server.stop(); + } + + private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/write?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void read(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/read?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void remove(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/remove?key=" + key; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals(value, response); + } + + private void invalidate(Executor executor) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/invalidate"; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + + private void recreate(Executor executor, String key, String value) throws IOException, ClientProtocolException { + String url = "http://localhost:8080/myapp/recreate?key=" + key + "&value=" + value; + String response = executor.execute(Request.Get(url)).returnContent().asString(); + Assert.assertEquals("OK", response); + } + +} diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TestServlet.java b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TestServlet.java new file mode 100644 index 000000000..1c68da965 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TestServlet.java @@ -0,0 +1,94 @@ +package org.redisson.tomcat; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class TestServlet extends HttpServlet { + + private static final long serialVersionUID = 1243830648280853203L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(); + + if (req.getPathInfo().equals("/write")) { + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/read")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + Object attr = session.getAttribute(key); + resp.getWriter().print(attr); + } else if (req.getPathInfo().equals("/remove")) { + String[] params = req.getQueryString().split("&"); + String key = null; + for (String param : params) { + String[] line = param.split("="); + String keyParam = line[0]; + if ("key".equals(keyParam)) { + key = line[1]; + } + } + + session.removeAttribute(key); + resp.getWriter().print(String.valueOf(session.getAttribute(key))); + } else if (req.getPathInfo().equals("/invalidate")) { + session.invalidate(); + + resp.getWriter().print("OK"); + } else if (req.getPathInfo().equals("/recreate")) { + session.invalidate(); + + session = req.getSession(); + + String[] params = req.getQueryString().split("&"); + String key = null; + String value = null; + for (String param : params) { + String[] paramLine = param.split("="); + String keyParam = paramLine[0]; + String valueParam = paramLine[1]; + + if ("key".equals(keyParam)) { + key = valueParam; + } + if ("value".equals(keyParam)) { + value = valueParam; + } + } + session.setAttribute(key, value); + + resp.getWriter().print("OK"); + } + } + +} diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TomcatServer.java b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TomcatServer.java new file mode 100644 index 000000000..16c6a25f9 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/java/org/redisson/tomcat/TomcatServer.java @@ -0,0 +1,64 @@ +package org.redisson.tomcat; + +import java.net.MalformedURLException; + +import javax.servlet.ServletException; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TomcatServer { + + private Tomcat tomcat = new Tomcat(); + private int port; + private boolean isRunning; + + private static final Logger LOG = LoggerFactory.getLogger(TomcatServer.class); + private static final boolean isInfo = LOG.isInfoEnabled(); + + public TomcatServer(String contextPath, int port, String appBase) throws MalformedURLException, ServletException { + if(contextPath == null || appBase == null || appBase.length() == 0) { + throw new IllegalArgumentException("Context path or appbase should not be null"); + } + if(!contextPath.startsWith("/")) { + contextPath = "/" + contextPath; + } + + tomcat.setBaseDir("."); // location where temp dir is created + tomcat.setPort(port); + tomcat.getHost().setAppBase("."); + + tomcat.addWebapp(contextPath, appBase + "webapp"); + } + + /** + * Start the tomcat embedded server + */ + public void start() throws LifecycleException { + tomcat.start(); + isRunning = true; + } + + /** + * Stop the tomcat embedded server + */ + public void stop() throws LifecycleException { + if(!isRunning) { + LOG.warn("Tomcat server is not running @ port={}", port); + return; + } + + if(isInfo) LOG.info("Stopping the Tomcat server"); + + tomcat.stop(); + tomcat.destroy(); + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + +} \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/webapp/META-INF/context.xml b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/META-INF/context.xml new file mode 100644 index 000000000..52b0eafd8 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/META-INF/context.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/redisson.yaml b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/redisson.yaml new file mode 100644 index 000000000..8f5de4111 --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/redisson.yaml @@ -0,0 +1,3 @@ +singleServerConfig: + address: + - "//127.0.0.1:6379" \ No newline at end of file diff --git a/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/web.xml b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..5940ccb8a --- /dev/null +++ b/redisson-tomcat/redisson-tomcat-8/src/test/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + testServlet + org.redisson.tomcat.TestServlet + 1 + + + + testServlet + /* + + + + 30 + + + diff --git a/redisson/header.txt b/redisson/header.txt deleted file mode 100644 index ac956a4f9..000000000 --- a/redisson/header.txt +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2016 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.