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

com.alachisoft.ncache.web.session.NCacheManager Maven / Gradle / Ivy

The newest version!
package com.alachisoft.ncache.web.session;

import Alachisoft.NCache.Common.Util.ReaderWriterLock;
import com.alachisoft.ncache.runtime.CacheItemPriority;
import com.alachisoft.ncache.runtime.caching.Tag;
import com.alachisoft.ncache.runtime.caching.expiration.Expiration;
import com.alachisoft.ncache.runtime.caching.expiration.ExpirationType;
import com.alachisoft.ncache.runtime.util.TimeSpan;
import com.alachisoft.ncache.web.CacheSession;
import com.alachisoft.ncache.web.EmptySession;
import com.alachisoft.ncache.web.LockException;
import com.alachisoft.ncache.client.Cache;
//[express]
import com.alachisoft.ncache.client.CacheItem;
//[endexpress]
import com.alachisoft.ncache.client.CacheItemVersion;
import com.alachisoft.ncache.client.LockHandle;
import com.alachisoft.ncache.client.CacheManager;
import com.alachisoft.ncache.web.config.dom.MultiSiteConfig;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
//import java.util.Hashtable; - sajid
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

public class NCacheManager {

    protected Cache cache = null;
    protected Logger logger = Logger.getLogger(NCacheManager.class);
    protected boolean lockRemoteSession = false;
    protected int lockTimeOut = 0;
    //private Hashtable locks = new Hashtable(); - sajid (Hashtable is replaced with HashMap)
    protected HashMap locks = new HashMap();
    protected int numberOfRetries = 0;
    protected int retryInterval = 0; // in milliseconds
    protected String _cacheId = null; // - sajid
    protected ReaderWriterLock _sync = new ReaderWriterLock();//synchronizes the cache operations and cache connection recycling.
    boolean _emptySessionWhenLocked = false;
    protected String _primaryCache="";
    protected String _currentSessionCache="";
    private String SESSION_TAG = "NCache_session_data";
    //--------------------------------------------------------------------------------------------------------
    public NCacheManager(String cacheId, boolean lockRemoteSession, int lockTimeOut, int numberOfRetries, int retryInterval, boolean emptySessions, String configPath, MultiSiteConfig settings) throws Exception {
        this.lockRemoteSession = lockRemoteSession;
        this.lockTimeOut = lockTimeOut;
        this.numberOfRetries = numberOfRetries;
        this.retryInterval = retryInterval;
        this._emptySessionWhenLocked = emptySessions;
        if (lockRemoteSession) {
            if (lockTimeOut < 0) {
                throw new IllegalArgumentException(NCacheSessionProvider.INITPARAM_LOCK_TIMEOUT + " must be a non-negative value: " + lockTimeOut);
            }
            if (numberOfRetries < 0) {
                throw new IllegalArgumentException(NCacheSessionProvider.INITPARAM_NUMBER_OF_RETRIES + " must be a non-negative value: " + numberOfRetries);
            }
            if (retryInterval < 0) {
                throw new IllegalArgumentException(NCacheSessionProvider.INITPARAM_RETRY_INTERVAL + " must be a non-negative value: " + retryInterval);
            }
        }
        this._cacheId = cacheId;
        this.initializeCache(cacheId, configPath, settings);
    }
    //--------------------------------------------------------------------------------------------------------

    public boolean initializeCache(String cacheId, String configPath, MultiSiteConfig settings) throws Exception {
        try {
            logger.debug("Initializing cache: " + cacheId);
            if (configPath != null) {
                logger.debug("Using cache config path: " + configPath);
                CacheManager.setConfigPath(configPath);
            }
            cache = CacheManager.getCache(cacheId);
            logger.debug("Cache [" + cacheId + "] is initialized successfully.");
            return true;
        } catch (Exception ex) {
            logger.error("Unable to initialize the cache [" + cacheId + "]. See log for more details.", ex);
            //return false;
            throw ex;
        }
    }
    //--------------------------------------------------------------------------------------------------------

    public void disconnect() {
        if (cache == null) {
            logger.debug("No valid cache instance to disconnect with.");
            //--- no need to stop. Cache not initialized
            return;
        }
        try {
            logger.debug("Disconnecting with cache: " + this._cacheId);
            cache.close();
            logger.debug("Successfully disconnected with cache: " + this._cacheId);
        } catch (Exception ex) {
            logger.error("Could not disconnect with cache [" + this._cacheId + "]. See log for more details.", ex);
        }
    }
    //--------------------------------------------------------------------------------------------------------

    public boolean isConnected() {
        boolean connected = cache != null;
        logger.debug("Is Connected with cache [" + this._cacheId + "]: " + connected);

        return connected;
    }
    //--------------------------------------------------------------------------------------------------------

    public void updateCacheItem(String key, Serializable item, int slicedExpiry, Cache cache) throws Exception {
        logger.debug("Updating cache item: " + key + " , with sliding expiration: " + slicedExpiry);
        CacheItem sessionItem = new CacheItem(item);
        List tag= new ArrayList<>(1);
        tag.add(new com.alachisoft.ncache.runtime.caching.Tag(SESSION_TAG));
        sessionItem.setTags(tag);
        if (cache != null) {
            try {
                if (slicedExpiry < 0) {
                    //--- if it is negative - never expire
                    logger.debug("Item will never expire.");
                    if (locks.get(key) != null) {
                        logger.debug("Will release the lock.");
                        sessionItem.setCacheItemPriority(CacheItemPriority.Default);
                        cache.insert(key, sessionItem, null,(LockHandle) locks.get(key), true);
                        locks.remove(key);
                    }
                } else {
                    logger.debug("Item will expire.");
                    if (locks.get(key) != null) {
                        logger.debug("Will release the lock.");
                        sessionItem.setCacheItemPriority(CacheItemPriority.Default);
                        sessionItem.setExpiration(new Expiration(ExpirationType.Sliding,new TimeSpan(0,0,slicedExpiry)));
                        CacheItemVersion version = cache.insert(key, sessionItem, null,(LockHandle) locks.get(key), true);
                        locks.remove(key);
                    } else {
                        sessionItem.setCacheItemPriority(CacheItemPriority.Default);
                        sessionItem.setExpiration(new Expiration(ExpirationType.Sliding,new TimeSpan(0,0,slicedExpiry)));
                        CacheItemVersion version = cache.insert(key, sessionItem, null,new LockHandle(), true);
                    }
                }
            } catch (Exception ex) {
                logger.error("Unable to update session [" + key + "] in cache [" + this._cacheId + "]. See logs for more details.", ex); // - sajid
                throw ex;
            }
        } else {
            logger.debug("Cache [" + cache + "] is not initialized.");
            throw new Exception("Cache [" + cache + "] is not initialized.");
        }
    }
    //--------------------------------------------------------------------------------------------------------

    public void removeCacheItem(String key, Cache cache) throws Exception {
        //logger.debug("Removing cache item: " + key);
        logger.debug("Removing session: " + key);
        if (cache != null) {
            try {
                //[express]
                if (locks.get(key) != null) {
                    cache.delete(key, (LockHandle) locks.get(key),null,null);
                    locks.remove(key);
                } else {
                    //[endexpress]
                    cache.delete(key);
                   //[express] 
                }
                //[endexpress]
                logger.debug("Session is removed.");
            } catch (Exception ex) {
                logger.error("Could not remove session. See log for more detail.", ex);
            }
        } else {
            logger.debug("Cache " + this._cacheId + " is not initialized.");
        }
    }
    //--------------------------------------------------------------------------------------------------------

    public Object getCacheItem(String key, Cache cache, int count) throws LockException, Exception {
        logger.debug("Getting session: " + key);
        if (cache != null) {
            try {
                Object obj = null;
                if (lockRemoteSession && _primaryCache.equalsIgnoreCase(_currentSessionCache)) {
                    LockHandle handle = new LockHandle();
                    //[express]
                    obj = cache.get(key, true,new TimeSpan(lockTimeOut), handle, null);
                    //[endexpress]
                    logger.debug("object is: " + obj + ", lockid is: " + handle.getLockId());
                    if (obj == null && (handle.getLockId() != null && handle.getLockId().length() > 0)) {
                        try {
                            count++;
                            if (count < this.numberOfRetries) {
                                logger.debug("Waiting ... for " + retryInterval + " ms");
                                Thread.sleep(this.retryInterval);
                                logger.debug("Retrying ... retry count: " + count);
                                if (SessionMonitor.getRequestCount(key) == 0) {
                                    logger.debug("Local Request Count is 0");
                                    return getCacheItem(key, cache, count);
                                } else {
                                    //--- somehow session has already been loaded by another request
                                    return null; //--- session is already locally new. No need to synch it
                                }
                            } else {
                                if (isEmptySession()) {
                                    return new EmptySession();
                                } else {
                                    logger.debug("Terminating ...");
                                    throw new LockException("Session is locked. please retry after few seconds.");
                                }
                            }
                        } catch (LockException le) {
                            throw le;
                        } catch (Exception exp) {
                            logger.debug("Could not get session: " + this._cacheId + ". See log for more details.", exp);
                        }
                    }
                    if (obj != null) {
                        locks.put(key, handle);
                    }
                } else {
                    obj = cache.get(key,null);
                }
                return obj;
            } catch (LockException le) {
                throw le;
            } catch (Exception ex) {
                //logger.debug("Could not get object for the given key. See log for more details.", ex);
                logger.debug("Could not get session: " + this._cacheId + ". See log for more details.", ex); // - sajid
                throw ex;
            }
        } else {
            logger.debug("Cache " + this._cacheId + " is not initialized.");
            throw new Exception(); // - sajid
        }

//        logger.debug("Returning null."); - sajid
//        return null; - sajid
    }
    //--------------------------------------------------------------------------------------------------------

    public CacheSession findSessionById(String sessionId) throws LockException, Exception {
        logger.debug("Trying to find session by id: " + sessionId);
        Object obj = getCacheItem(sessionId, cache, 0);
        if (obj != null && obj instanceof CacheSession) {
            logger.debug("Found valid session object.");
            return (CacheSession) obj;
        }
        //logger.debug("Could not find a valid session object. Returning null.");
        logger.debug("Could not find session [" + sessionId + "] in cache [" + this._cacheId + "]. Returning null."); // - sajid

        return null;
    }
    //--------------------------------------------------------------------------------------------------------

    /**
     * This method tracks Session stored on JvCache server using different
     * techniques. If finds an already stored session, fills the local session
     * with attributes from JvCache copy. Otherwise creates a new session on
     * JvCache server. Here is the algorithm it uses to initialize the session:
     * ------------------------------------------------------------------------------------------
     * | If local session is new try to find a CacheSession. (This may be
     * because | | loadbalancer moved the request to a new node) | | if no
     * CacheSession exists by local session id, try to find a requested session.
     * | | (May be the new node created a different session object) | | if still
     * no CacheSession found, create a new one and add to cache. | | | | if
     * local session is not new, simply try to find a CacheSession by local
     * session ID. | | If no session found, create a new one and add it to
     * cache. | | | | Finally, copy all the attributes from CacheSession to the
     * local session. |
     * ------------------------------------------------------------------------------------------
     *
     * Initialize the session to the JvCache
     *
     * @param request instance of the HttpServletRequest that CONTAINER passed
     * to the filter
     * @return An instance of CacheSessiion saved to JvCache that can be later
     * on updated once the chain has finished execution
     */
    public CacheSession initializeCacheSession(HttpServletRequest request, CacheSession csession) throws LockException {
        logger.debug("Initializing sessioin for request -> " + request.getRemoteAddr() + ":" + request.getRemotePort());

        HttpSession session = request.getSession(false);
        if (session == null) {
            return csession;
        }

        String validSessionId = (csession != null ? csession.getSessionId() : null);
        if (validSessionId == null) {
            validSessionId = session.getId();
        }

        //--- still null? Create new one and add to the
        if (csession == null) {
            logger.debug("Creating new session with id: " + getPrimaryPrefix() + session.getId());
            csession = new CacheSession(getPrimaryPrefix());
            csession.setSessionId(validSessionId);
            csession.setMaxInactiveInterval(session.getMaxInactiveInterval());
        }
        SessionMonitor.addRequest(csession.getSessionId());

        return csession;
    }
    //--------------------------------------------------------------------------------------------------------

    /**
     * This method updates the state of the session in cache.Here is the
     * algorithm that is used to update the state:
     *
     * --------------------------------------------------------------------------------------
     * | If local session is null (because it has been invalidated) | | remove
     * the session from cache. | | | | Otherwise, if local session id does not
     * match with the one we have in cache | | (session invalidated and created
     * a new one) | | | | Remove the old session and add a new CacheSesion in
     * cache (In fact, just | | change the session id of the cache entry so that
     * it now can be tracked using | | new session id, rest of the state will be
     * updated later | | | | Finally, copy all the attributes from local session
     * to the CacheSession and | | update it on the JvCache server. Also clear
     * the attribute list of the local session.|
     * ---------------------------------------------------------------------------------------
     *
     * @param session
     * @param csession
     */
    public void finalizeCacheSession(HttpSession session, CacheSession csession) throws Exception {
        logger.debug("Finalizing session ..");
        if (session == null) {
            Cache cache = getCache();
            //--- csession is not valid. We should remove the csession from cache.
            this.removeCacheItem(csession.getSessionId(), cache);
            logger.debug("Session invalidated. Removing from cache: " + this._cacheId);
            //-- what next? exit
            return;
        }
        //--- remove the requestCount from session monitor
        SessionMonitor.removeRequest(csession.getSessionId());
        //--- check if another request is using the same session? If yes, do not save the session state for now
        if (SessionMonitor.getRequestCount(csession.getSessionId()) == 0 && csession.updateToCache()) {
            //--- get attributes list
            logger.debug("Filling the session attributes...");
            Enumeration names = session.getAttributeNames();
            while (names.hasMoreElements()) {
                String key = (String) names.nextElement();
                logger.debug("Updating key: " + key);
                csession.setAttribute(key, session.getAttribute(key));
                logger.debug("Removing key [" + key + "] from local session");
                session.removeAttribute(key);
            }
            //--- session is no longer new
            csession.setIsNew(false);
            csession.setMaxInactiveInterval(session.getMaxInactiveInterval());
            //--- now update the cache
            logger.debug("Saving session state...");
            //getting current primary cache instance for multi site cache
            //Cache cache = getCache(csession.getSessionId(), true);
            this.updateCacheItem(csession.getSessionId(), csession, session.getMaxInactiveInterval(), cache);
        }
    }
    //--------------------------------------------------------------------------------------------------------

    public CacheSession findValidRemoteSession(HttpServletRequest request, String[] expectedKeys) throws LockException {
        if (expectedKeys == null) {
            return null;
        }
        CacheSession cs = null;
        for (int i = 0; i < expectedKeys.length; i++) {
            if (expectedKeys[i] == null || expectedKeys[i].trim().length() == 0) {
                continue;
            }
            try {
                cs = findSessionById(expectedKeys[i].trim());
                if (cs != null) {
                    //Updating session id according to current primary cache prefix
                    cs.setPrefix(getPrimaryPrefix());
                    cs = initializeCacheSession(request, cs);
                    break;
                }
            } catch (Exception exp) {
            }
        }

        if (cs == null) {
            //--- cs still null? could be either non-existant or locally available.
            for (int i = 0; i < expectedKeys.length; i++) {
                if (expectedKeys[i] == null || expectedKeys[i].trim().length() == 0) {
                    continue;
                }
                if (SessionMonitor.getRequestCount(expectedKeys[i].trim()) > 0) {
                    cs = new CacheSession(getPrimaryPrefix());
                    cs.setSessionId(expectedKeys[i].trim());
                    break;
                }
            }
        }

        return cs;
    }
    //--------------------------------------------------------------------------------------------------------

    public String getPrimaryPrefix() {
        return "";
    }
    //--------------------------------------------------------------------------------------------------------

    public Cache getCache() {
        return cache;
    }
    //--------------------------------------------------------------------------------------------------------

    public boolean isEmptySession() {
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy