Package com.dawsonsystems.session

Source Code of com.dawsonsystems.session.MongoManager

/***********************************************************************************************************************
*
* Mongo Tomcat Sessions
* ==========================================
*
* Copyright (C) 2012 by Dawson Systems Ltd (http://www.dawsonsystems.com)
*
***********************************************************************************************************************
*
* 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 com.dawsonsystems.session;

import com.mongodb.*;
import org.apache.catalina.*;
import org.apache.catalina.session.StandardSession;

import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MongoManager implements Manager, Lifecycle {
  private static Logger log = Logger.getLogger("MongoManager");
  protected static String host = "localhost";
  protected static int port = 27017;
  protected static String database = "sessions";
  protected Mongo mongo;
  protected DB db;
  protected boolean slaveOk;

  private MongoSessionTrackerValve trackerValve;
  private ThreadLocal<StandardSession> currentSession = new ThreadLocal<StandardSession>();
  private Serializer serializer;

  //Either 'kryo' or 'java'
  private String serializationStrategyClass = "com.dawsonsystems.session.JavaSerializer";

  private Container container;
  private int maxInactiveInterval;

  @Override
  public Container getContainer() {
    return container;
  }

  @Override
  public void setContainer(Container container) {
    this.container = container;
  }

  @Override
  public boolean getDistributable() {
    return false;
  }

  @Override
  public void setDistributable(boolean b) {

  }

  @Override
  public String getInfo() {
    return "Mongo Session Manager";
  }

  @Override
  public int getMaxInactiveInterval() {
    return maxInactiveInterval;
  }

  @Override
  public void setMaxInactiveInterval(int i) {
    maxInactiveInterval = i;
  }

  @Override
  public int getSessionIdLength() {
    return 37;
  }

  @Override
  public void setSessionIdLength(int i) {

  }

  @Override
  public int getSessionCounter() {
    return 10000000;
  }

  @Override
  public void setSessionCounter(int i) {

  }

  @Override
  public int getMaxActive() {
    return 1000000;
  }

  @Override
  public void setMaxActive(int i) {

  }

  @Override
  public int getActiveSessions() {
    return 1000000;
  }

  @Override
  public int getExpiredSessions() {
    return 0;
  }

  @Override
  public void setExpiredSessions(int i) {

  }

  public int getRejectedSessions() {
    return 0;
  }

  public void setSerializationStrategyClass(String strategy) {
    this.serializationStrategyClass = strategy;
  }

  public void setSlaveOk(boolean slaveOk) {
    this.slaveOk = slaveOk;
  }

  public boolean getSlaveOk() {
    return slaveOk;
  }

  public void setRejectedSessions(int i) {
  }

  @Override
  public int getSessionMaxAliveTime() {
    return maxInactiveInterval;
  }

  @Override
  public void setSessionMaxAliveTime(int i) {

  }

  @Override
  public int getSessionAverageAliveTime() {
    return 0;
  }

  @Override
  public void setSessionAverageAliveTime(int i) {

  }

  public void load() throws ClassNotFoundException, IOException {
  }

  public void unload() throws IOException {
  }

  @Override
  public void backgroundProcess() {
    processExpires();
  }

  public void addLifecycleListener(LifecycleListener lifecycleListener) {
  }

  public LifecycleListener[] findLifecycleListeners() {
    return new LifecycleListener[0]//To change body of implemented methods use File | Settings | File Templates.
  }

  public void removeLifecycleListener(LifecycleListener lifecycleListener) {
  }

  @Override
  public void add(Session session) {
    try {
      save(session);
    } catch (IOException ex) {
      log.log(Level.SEVERE, "Error adding new session", ex);
    }
  }

  @Override
  public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    //To change body of implemented methods use File | Settings | File Templates.
  }

  @Override
  public void changeSessionId(Session session) {
    session.setId(UUID.randomUUID().toString());
  }

  @Override
  public Session createEmptySession() {
    MongoSession session = new MongoSession(this);
    session.setId(UUID.randomUUID().toString());
    session.setMaxInactiveInterval(maxInactiveInterval);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setNew(true);
    currentSession.set(session);
    log.fine("Created new empty session " + session.getIdInternal());
    return session;
  }

  /**
   * @deprecated
   */
  public org.apache.catalina.Session createSession() {
    return createEmptySession();
  }

  public org.apache.catalina.Session createSession(java.lang.String sessionId) {
    StandardSession session = (MongoSession) createEmptySession();

    log.fine("Created session with id " + session.getIdInternal() + " ( " + sessionId + ")");
    if (sessionId != null) {
      session.setId(sessionId);
    }

    return session;
  }

  public org.apache.catalina.Session[] findSessions() {
    try {
      List<Session> sessions = new ArrayList<Session>();
      for(String sessionId : keys()) {
        sessions.add(loadSession(sessionId));
      }
      return sessions.toArray(new Session[sessions.size()]);
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    }
  }

  protected org.apache.catalina.session.StandardSession getNewSession() {
    log.fine("getNewSession()");
    return (MongoSession) createEmptySession();
  }

  public void start() throws LifecycleException {
    for (Valve valve : getContainer().getPipeline().getValves()) {
      if (valve instanceof MongoSessionTrackerValve) {
        trackerValve = (MongoSessionTrackerValve) valve;
        trackerValve.setMongoManager(this);
        log.info("Attached to Mongo Tracker Valve");
        break;
      }
    }
    try {
      initSerializer();
    } catch (ClassNotFoundException e) {
      log.log(Level.SEVERE, "Unable to load serializer", e);
      throw new LifecycleException(e);
    } catch (InstantiationException e) {
      log.log(Level.SEVERE, "Unable to load serializer", e);
      throw new LifecycleException(e);
    } catch (IllegalAccessException e) {
      log.log(Level.SEVERE, "Unable to load serializer", e);
      throw new LifecycleException(e);
    }
    log.info("Will expire sessions after " + getMaxInactiveInterval() + " seconds");
    initDbConnection();
  }

  public void stop() throws LifecycleException {
    mongo.close();
  }

  public Session findSession(String id) throws IOException {
    return loadSession(id);
  }

  public static String getHost() {
    return host;
  }

  public static void setHost(String host) {
    MongoManager.host = host;
  }

  public static int getPort() {
    return port;
  }

  public static void setPort(int port) {
    MongoManager.port = port;
  }

  public static String getDatabase() {
    return database;
  }

  public static void setDatabase(String database) {
    MongoManager.database = database;
  }

  public void clear() throws IOException {
    getCollection().drop();
    getCollection().ensureIndex(new BasicDBObject("lastmodified", 1));
  }

  private DBCollection getCollection() throws IOException {
    return db.getCollection("sessions");
  }

  public int getSize() throws IOException {
    return (int) getCollection().count();
  }

  public String[] keys() throws IOException {

    BasicDBObject restrict = new BasicDBObject();
    restrict.put("_id", 1);

    DBCursor cursor = getCollection().find(new BasicDBObject(), restrict);

    List<String> ret = new ArrayList<String>();

    while (cursor.hasNext()) {
      ret.add(cursor.next().get("").toString());
    }

    return ret.toArray(new String[ret.size()]);
  }


  public Session loadSession(String id) throws IOException {

    if (id == null || id.length() == 0) {
      return createEmptySession();
    }

    StandardSession session = currentSession.get();

    if (session != null) {
      if (id.equals(session.getId())) {
        return session;
      } else {
        currentSession.remove();
      }
    }
    try {
      log.fine("Loading session " + id + " from Mongo");
      BasicDBObject query = new BasicDBObject();
      query.put("_id", id);

      DBObject dbsession = getCollection().findOne(query);

      if (dbsession == null) {
        log.fine("Session " + id + " not found in Mongo");
        StandardSession ret = getNewSession();
        ret.setId(id);
        currentSession.set(ret);
        return ret;
      }

      byte[] data = (byte[]) dbsession.get("data");

      session = (MongoSession) createEmptySession();
      session.setId(id);
      session.setManager(this);
      serializer.deserializeInto(data, session);

      session.setMaxInactiveInterval(-1);
      session.access();
      session.setValid(true);
      session.setNew(false);

      if (log.isLoggable(Level.FINE)) {
        log.fine("Session Contents [" + session.getId() + "]:");
        for (Object name : Collections.list(session.getAttributeNames())) {
          log.fine("  " + name);
        }
      }

      log.fine("Loaded session id " + id);
      currentSession.set(session);
      return session;
    } catch (IOException e) {
      log.severe(e.getMessage());
      throw e;
    } catch (ClassNotFoundException ex) {
      log.log(Level.SEVERE, "Unable to deserialize session ", ex);
      throw new IOException("Unable to deserializeInto session", ex);
    }
  }

  public void save(Session session) throws IOException {
    try {
      log.fine("Saving session " + session + " into Mongo");

      StandardSession standardsession = (MongoSession) session;

      if (log.isLoggable(Level.FINE)) {
        log.fine("Session Contents [" + session.getId() + "]:");
        for (Object name : Collections.list(standardsession.getAttributeNames())) {
          log.fine("  " + name);
        }
      }

      byte[] data = serializer.serializeFrom(standardsession);

      BasicDBObject dbsession = new BasicDBObject();
      dbsession.put("_id", standardsession.getId());
      dbsession.put("data", data);
      dbsession.put("lastmodified", System.currentTimeMillis());

      BasicDBObject query = new BasicDBObject();
      query.put("_id", standardsession.getIdInternal());
      getCollection().update(query, dbsession, true, false);
      log.fine("Updated session with id " + session.getIdInternal());
    } catch (IOException e) {
      log.severe(e.getMessage());
      e.printStackTrace();
      throw e;
    } finally {
      currentSession.remove();
      log.fine("Session removed from ThreadLocal :" + session.getIdInternal());
    }
  }

  public void remove(Session session) {
    log.fine("Removing session ID : " + session.getId());
    BasicDBObject query = new BasicDBObject();
    query.put("_id", session.getId());

    try {
      getCollection().remove(query);
    } catch (IOException e) {
      log.log(Level.SEVERE, "Error removing session in Mongo Session Store", e);
    } finally {
      currentSession.remove();
    }
  }

  @Override
  public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    //To change body of implemented methods use File | Settings | File Templates.
  }

  public void processExpires() {
    BasicDBObject query = new BasicDBObject();

    long olderThan = System.currentTimeMillis() - (getMaxInactiveInterval() * 1000);

    log.fine("Looking for sessions less than for expiry in Mongo : " + olderThan);

    query.put("lastmodified", new BasicDBObject("$lt", olderThan));

    try {
      WriteResult result = getCollection().remove(query);
      log.fine("Expired sessions : " + result.getN());
    } catch (IOException e) {
      log.log(Level.SEVERE, "Error cleaning session in Mongo Session Store", e);
    }
  }

  private void initDbConnection() throws LifecycleException {
    try {
      String[] hosts = getHost().split(",");

      List<ServerAddress> addrs = new ArrayList<ServerAddress>();

      for (String host : hosts) {
        addrs.add(new ServerAddress(host, getPort()));
      }
      mongo = new Mongo(addrs);
      db = mongo.getDB(getDatabase());
      if (slaveOk) {
        db.slaveOk();
      }
      getCollection().ensureIndex(new BasicDBObject("lastmodified", 1));
      log.info("Connected to Mongo " + host + "/" + database + " for session storage, slaveOk=" + slaveOk + ", " + (getMaxInactiveInterval() * 1000) + " session live time");
    } catch (IOException e) {
      e.printStackTrace();
      throw new LifecycleException("Error Connecting to Mongo", e);
    }
  }

  private void initSerializer() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    log.info("Attempting to use serializer :" + serializationStrategyClass);
    serializer = (Serializer) Class.forName(serializationStrategyClass).newInstance();

    Loader loader = null;

    if (container != null) {
      loader = container.getLoader();
    }
    ClassLoader classLoader = null;

    if (loader != null) {
      classLoader = loader.getClassLoader();
    }
    serializer.setClassLoader(classLoader);
  }
}
TOP

Related Classes of com.dawsonsystems.session.MongoManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.