Tomcat session manager implemented. #590
parent
7c0ac961e7
commit
c378299009
@ -0,0 +1,61 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-parent</artifactId>
|
||||||
|
<version>2.6.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>redisson-tomcat</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>Redisson/Tomcat</name>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>redisson-tomcat-6</module>
|
||||||
|
<module>redisson-tomcat-7</module>
|
||||||
|
<module>redisson-tomcat-8</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>2.10.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-javadocs</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>fluent-hc</artifactId>
|
||||||
|
<version>4.5.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,64 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-tomcat</artifactId>
|
||||||
|
<version>2.6.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>redisson-tomcat-6</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Redisson/Tomcat-6</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>catalina</artifactId>
|
||||||
|
<version>6.0.48</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.mycila</groupId>
|
||||||
|
<artifactId>license-maven-plugin</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
<configuration>
|
||||||
|
<basedir>${basedir}</basedir>
|
||||||
|
<header>${basedir}/../../header.txt</header>
|
||||||
|
<quiet>false</quiet>
|
||||||
|
<failIfMissing>true</failIfMissing>
|
||||||
|
<aggregate>false</aggregate>
|
||||||
|
<includes>
|
||||||
|
<include>src/main/java/org/redisson/</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>target/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
<useDefaultExcludes>true</useDefaultExcludes>
|
||||||
|
<mapping>
|
||||||
|
<java>JAVADOC_STYLE</java>
|
||||||
|
</mapping>
|
||||||
|
<strictCheck>true</strictCheck>
|
||||||
|
<useDefaultMapping>true</useDefaultMapping>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
@ -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<String, Object> 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<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
map.fastRemove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
RMap<String, Object> 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<String, Object> entry : attributes.entrySet()) {
|
||||||
|
map.fastPut(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
RMap<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
if (!map.isExists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Entry<String, Object>> entrySet = map.readAllEntrySet();
|
||||||
|
for (Entry<String, Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<String, Object> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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:
|
||||||
|
* <pre><Server>
|
||||||
|
* <Service>
|
||||||
|
* <Connector />
|
||||||
|
* <Engine>
|
||||||
|
* <Host>
|
||||||
|
* <Context />
|
||||||
|
* </Host>
|
||||||
|
* </Engine>
|
||||||
|
* </Service>
|
||||||
|
*</Server></pre>
|
||||||
|
* <Server> & <Service> 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: <code>/src/main/</code>)
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<Context>
|
||||||
|
|
||||||
|
<Manager className="org.redisson.tomcat.RedissonSessionManager"
|
||||||
|
configPath="${catalina.base}/src/test/webapp/WEB-INF/redisson.yaml" />
|
||||||
|
|
||||||
|
</Context>
|
@ -0,0 +1,3 @@
|
|||||||
|
singleServerConfig:
|
||||||
|
address:
|
||||||
|
- "//127.0.0.1:6379"
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||||
|
version="2.5">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<servlet-class>org.redisson.tomcat.TestServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<session-config>
|
||||||
|
<session-timeout>30</session-timeout>
|
||||||
|
</session-config>
|
||||||
|
|
||||||
|
</web-app>
|
@ -0,0 +1,82 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-tomcat</artifactId>
|
||||||
|
<version>2.6.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>redisson-tomcat-7</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Redisson/Tomcat-7</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>7.0.73</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||||
|
<version>7.0.73</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-jasper</artifactId>
|
||||||
|
<version>7.0.73</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-jasper</artifactId>
|
||||||
|
<version>7.0.73</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.mycila</groupId>
|
||||||
|
<artifactId>license-maven-plugin</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
<configuration>
|
||||||
|
<basedir>${basedir}</basedir>
|
||||||
|
<header>${basedir}/../../header.txt</header>
|
||||||
|
<quiet>false</quiet>
|
||||||
|
<failIfMissing>true</failIfMissing>
|
||||||
|
<aggregate>false</aggregate>
|
||||||
|
<includes>
|
||||||
|
<include>src/main/java/org/redisson/</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>target/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
<useDefaultExcludes>true</useDefaultExcludes>
|
||||||
|
<mapping>
|
||||||
|
<java>JAVADOC_STYLE</java>
|
||||||
|
</mapping>
|
||||||
|
<strictCheck>true</strictCheck>
|
||||||
|
<useDefaultMapping>true</useDefaultMapping>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
@ -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<String, Object> 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<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
map.fastRemove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
RMap<String, Object> 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<String, Object> entry : attributes.entrySet()) {
|
||||||
|
map.fastPut(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
RMap<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
if (!map.isExists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Entry<String, Object>> entrySet = map.readAllEntrySet();
|
||||||
|
for (Entry<String, Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<String, Object> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<Context>
|
||||||
|
|
||||||
|
<Manager className="org.redisson.tomcat.RedissonSessionManager"
|
||||||
|
configPath="${catalina.base}/src/test/webapp/WEB-INF/redisson.yaml" />
|
||||||
|
|
||||||
|
</Context>
|
@ -0,0 +1,3 @@
|
|||||||
|
singleServerConfig:
|
||||||
|
address:
|
||||||
|
- "//127.0.0.1:6379"
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||||
|
version="2.5">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<servlet-class>org.redisson.tomcat.TestServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<session-config>
|
||||||
|
<session-timeout>30</session-timeout>
|
||||||
|
</session-config>
|
||||||
|
|
||||||
|
</web-app>
|
@ -0,0 +1,81 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-tomcat</artifactId>
|
||||||
|
<version>2.6.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>redisson-tomcat-8</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Redisson/Tomcat-8</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>8.0.39</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||||
|
<version>8.0.39</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-jasper</artifactId>
|
||||||
|
<version>8.0.39</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-jasper</artifactId>
|
||||||
|
<version>8.0.39</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.mycila</groupId>
|
||||||
|
<artifactId>license-maven-plugin</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
<configuration>
|
||||||
|
<basedir>${basedir}</basedir>
|
||||||
|
<header>${basedir}/../../header.txt</header>
|
||||||
|
<quiet>false</quiet>
|
||||||
|
<failIfMissing>true</failIfMissing>
|
||||||
|
<aggregate>false</aggregate>
|
||||||
|
<includes>
|
||||||
|
<include>src/main/java/org/redisson/</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>target/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
<useDefaultExcludes>true</useDefaultExcludes>
|
||||||
|
<mapping>
|
||||||
|
<java>JAVADOC_STYLE</java>
|
||||||
|
</mapping>
|
||||||
|
<strictCheck>true</strictCheck>
|
||||||
|
<useDefaultMapping>true</useDefaultMapping>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -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<String, Object> 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<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
map.fastRemove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
RMap<String, Object> 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<String, Object> entry : attributes.entrySet()) {
|
||||||
|
map.fastPut(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
RMap<String, Object> map = redissonManager.getMap(getId());
|
||||||
|
if (!map.isExists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Entry<String, Object>> entrySet = map.readAllEntrySet();
|
||||||
|
for (Entry<String, Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<String, Object> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<Context>
|
||||||
|
|
||||||
|
<Manager className="org.redisson.tomcat.RedissonSessionManager"
|
||||||
|
configPath="${catalina.base}/src/test/webapp/WEB-INF/redisson.yaml" />
|
||||||
|
|
||||||
|
</Context>
|
@ -0,0 +1,3 @@
|
|||||||
|
singleServerConfig:
|
||||||
|
address:
|
||||||
|
- "//127.0.0.1:6379"
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||||
|
version="2.5">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<servlet-class>org.redisson.tomcat.TestServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>testServlet</servlet-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<session-config>
|
||||||
|
<session-timeout>30</session-timeout>
|
||||||
|
</session-config>
|
||||||
|
|
||||||
|
</web-app>
|
@ -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.
|
|
Loading…
Reference in New Issue