All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.docshare.boot.RedisSessionDataMap Maven / Gradle / Ivy

package org.docshare.boot;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.docshare.log.Log;
import org.docshare.mvc.Config;
import org.eclipse.jetty.server.session.SessionContext;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.SessionDataMap;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;
import redis.clients.util.JedisURIHelper;

/**
 * RedisSessionDataMap
 *
 * Uses redis as a cache for SessionData
 */
@ManagedObject
public class RedisSessionDataMap extends AbstractLifeCycle implements SessionDataMap {
    public static final String DEFAULT_HOST = "localhost";
    public static final String DEFAULT_PORT = "6379";
    protected SessionContext _context; //context associated with this session data map
    protected JedisPool _pool;
    protected int _expirySec = 0;
    protected String _host;
    protected int _port;
    protected int _connectionTimeout = Protocol.DEFAULT_TIMEOUT;
    protected int _soTimeout = Protocol.DEFAULT_TIMEOUT;
    protected String _password;
    protected int _database = Protocol.DEFAULT_DATABASE;
    protected String _clientName;
    protected boolean _ssl;
    protected SSLSocketFactory _sslSocketFactory;
    protected SSLParameters _sslParameters;
    protected HostnameVerifier _hostnameVerifier;
    protected int _maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
    protected int _minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
    protected int _maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
    protected String _keyPrefix;
    protected boolean _compression = false;

    /**
     * @param host address of memcache server
     * @param port address of memcache server
     */
    public RedisSessionDataMap() {
        String redis_host = Config.getProperty("redis_host", "localhost");
        String redis_port = Config.getProperty("redis_port","6379");
        setRedis(redis_host,redis_port);
    }
    public void setRedis(String host,String port){
        if (host == null || port == null) {
            throw new IllegalArgumentException("Host: " + host + " port: " + port);
        }
        _host = host;
        int v;
        try {
            v = Integer.parseInt(port);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Port: " + port, e);
        }
        if (v <= 0 || v > 65535) {
            throw new IllegalArgumentException("Port: " + v);
        }
        _port = v;
    }

    /**
     * @param sec the expiry to use in seconds
     */
    public void setExpirySec(int sec) {
        _expirySec = sec;
    }

    /**
     * Expiry time for memached entries.
     *
     * @return memcached expiry time in sec
     */
    @ManagedAttribute(value = "redis expiry time in sec", readonly = true)
    public int getExpirySec() {
        return _expirySec;
    }

    public String getHost() {
        return _host;
    }

    public void setHost(String host) {
        this._host = host;
    }

    public int getPort() {
        return _port;
    }

    public void setPort(int port) {
        this._port = port;
    }

    public String getUrl() {
        return (_ssl ? "rediss" : "redis") + "://" + (_password == null ? null : ":" + _password + "@") + _host + ":"
                + _port + (_database != Protocol.DEFAULT_DATABASE ? "/" + _database : "/");
    }

    public void setUrl(String url) {
        URI uri = URI.create(url);
        if (JedisURIHelper.isValid(uri)) {
            setHost(uri.getHost());
            setPort(uri.getPort());
            setPassword(JedisURIHelper.getPassword(uri));
            setDatabase(JedisURIHelper.getDBIndex(uri));
            setSSL(uri.getScheme().equals("rediss"));
        } else {
            throw new IllegalArgumentException("Url: " + url);
        }
    }

    public int getConnectionTimeout() {
        return _connectionTimeout;
    }

    public void setConnectionTimeout(int connectionTimeout) {
        this._connectionTimeout = connectionTimeout;
    }

    public int getSoTimeout() {
        return _soTimeout;
    }

    public void setSoTimeout(int soTimeout) {
        this._soTimeout = soTimeout;
    }

    public String getPassword() {
        return _password;
    }

    public void setPassword(String password) {
        this._password = password;
    }

    public int getDatabase() {
        return _database;
    }

    public void setDatabase(int database) {
        this._database = database;
    }

    public String getClientName() {
        return _clientName;
    }

    public void setClientName(String clientName) {
        this._clientName = clientName;
    }

    public boolean isSSL() {
        return _ssl;
    }

    public void setSSL(boolean ssl) {
        this._ssl = ssl;
    }

    public SSLSocketFactory getSSLSocketFactory() {
        return _sslSocketFactory;
    }

    public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
        this._sslSocketFactory = sslSocketFactory;
    }

    public SSLParameters getSSLParameters() {
        return _sslParameters;
    }

    public void setSSLParameters(SSLParameters sslParameters) {
        this._sslParameters = sslParameters;
    }

    public HostnameVerifier getHostnameVerifier() {
        return _hostnameVerifier;
    }

    public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
        this._hostnameVerifier = hostnameVerifier;
    }

    public int getMaxIdle() {
        return _maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this._maxIdle = maxIdle;
    }

    public int getMinIdle() {
        return _minIdle;
    }

    public void setMinIdle(int minIdle) {
        this._minIdle = minIdle;
    }

    public int getMaxTotal() {
        return _maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this._maxTotal = maxTotal;
    }

    public String getKeyPrefix() {
        return _keyPrefix;
    }

    public void setKeyPrefix(String keyPrefix) {
        this._keyPrefix = keyPrefix;
    }

    public boolean isCompression() {
        return _compression;
    }

    public void setCompression(boolean compression) {
        this._compression = compression;
    }

    /**
     * @see SessionDataMap#initialize(SessionContext)
     */
    @Override
    public void initialize(SessionContext context) {
        if (isStarted()) {
            throw new IllegalStateException("Context set after RedisSessionDataMap started");
        }
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxIdle(_maxIdle);
        poolConfig.setMinIdle(_minIdle);
        poolConfig.setMaxTotal(_maxTotal);
        _pool = new JedisPool(poolConfig, _host, _port, _connectionTimeout, _soTimeout,
                _password, _database, _clientName, _ssl, _sslSocketFactory, _sslParameters, _hostnameVerifier);
        _context = context;
    }

    /**
     * @see SessionDataMap#load(java.lang.String)
     */
    @Override
    public SessionData load(String id) throws Exception {
        Log.d("RedisSessionDataMap load "+id);
        if (!isStarted()) {
            throw new IllegalStateException("Not started");
        }
        final AtomicReference reference = new AtomicReference();
        final AtomicReference exception = new AtomicReference();

        Runnable r = () ->
        {
            try {
                byte[] bytes;
                try (Jedis jedis = _pool.getResource()) {
                    bytes = jedis.get(keyAsBytes(id));
                }
                if (bytes == null || bytes.length < 4) {
                    reference.set(null);
                    return;
                }
                try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                     InputStream in = _compression ? new InflaterInputStream(bais) : null;
                     ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(_compression ? in : bais);) {
                    long created = ois.readLong();
                    long accessed = ois.readLong();
                    long lastAccessed = ois.readLong();
                    long maxIdle = ois.readLong();
                    SessionData data =
                            new SessionData(id, _context.getCanonicalContextPath(), _context.getVhost(), created,
                                    accessed, lastAccessed, maxIdle);
                    SessionData.deserializeAttributes(data, ois);
                    reference.set(data);
                }
            } catch (Exception e) {
                exception.set(e);
            }
        };

        _context.run(r);
        if (exception.get() != null)
            throw exception.get();

        return reference.get();
    }

    private byte[] keyAsBytes(String id) {
        id= "rsess_"+id;
        if (_keyPrefix == null) {
            return id.getBytes(StandardCharsets.UTF_8);
        } else {
            return (_keyPrefix + id).getBytes(StandardCharsets.UTF_8);
        }
    }


    /**
     * @see SessionDataMap#store(java.lang.String, SessionData)
     */
    @Override
    public void store(String id, SessionData data) throws Exception {

        Log.d("RedisSessionDataMap store "+id);
        if (!isStarted()) {
            throw new IllegalStateException("Not started");
        }
        if (data == null) {
            return;
        }

        final AtomicReference exception = new AtomicReference();

        Runnable r = () -> {
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                try (DeflaterOutputStream out = _compression ? new DeflaterOutputStream(baos) : null;
                     ObjectOutputStream oos = new ObjectOutputStream(_compression ? out : baos)) {
                    oos.writeLong(data.getCreated());
                    oos.writeLong(data.getAccessed());
                    oos.writeLong(data.getLastAccessed());
                    oos.writeLong(data.getMaxInactiveMs());
                    SessionData.serializeAttributes(data, oos);
                }
                byte[] bytes = baos.toByteArray();
                try (Jedis jedis = _pool.getResource()) {
                    if (_expirySec > 0) {
                        jedis.setex(keyAsBytes(id), _expirySec, bytes);
                    } else {
                        jedis.set(keyAsBytes(id), bytes);
                    }

                }
            } catch (Exception e) {
                exception.set(e);
            }
        };

        _context.run(r);
        if (exception.get() != null) {
            throw exception.get();
        }
    }


    /**
     * @see SessionDataMap#delete(java.lang.String)
     */
    @Override
    public boolean delete(String id) throws Exception {

        Log.d("RedisSessionDataMap delete "+id);
        if (!isStarted()) {
            throw new IllegalStateException("Not started");
        }
        try (Jedis jedis = _pool.getResource()) {
            return jedis.del(keyAsBytes(id)) > 0;
        }
    }

    @Override
    protected void doStart() throws Exception {
        if (_context == null)
            throw new IllegalStateException("No SessionContext");

        super.doStart();
    }


    @Override
    protected void doStop() throws Exception {
        super.doStop();
        if (_pool != null) {
            _pool.close();
            ;
            _pool = null;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy