/FileExtraction/Java_unseen/dlitz_resin/modules/resin/src/com/caucho/server/distcache/CacheConfig.java
/*
 * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.server.distcache;

import com.caucho.config.Configurable;
import com.caucho.distcache.AbstractCache;
import com.caucho.distcache.CacheSerializer;
import com.caucho.distcache.HessianSerializer;
import com.caucho.distcache.ResinCacheBuilder.Scope;
import com.caucho.util.Alarm;
import com.caucho.util.HashKey;

import javax.cache.CacheLoader;

/**
 * Manages the distributed cache
 */
public class CacheConfig
{
  public static final long TIME_INFINITY  = Long.MAX_VALUE / 2;
  public static final long TIME_HOUR  = 3600 * 1000L;
  public static final int FLAG_TRANSIENT  = 0x01;
  public static final int FLAG_BACKUP = 0x02;
  public static final int FLAG_TRIPLICATE = 0x04;
  
  public static final int FLAG_CLUSTER = 0x08;
  public static final int FLAG_GLOBAL = 0x10;

  private String _guid;
  private HashKey _cacheKey;

  private int _flags = (FLAG_BACKUP | FLAG_TRIPLICATE);

  private long _modifiedExpireTimeout = TIME_INFINITY;
  private long _modifiedExpireTimeoutWindow = 0;

  private long _accessedExpireTimeout = TIME_INFINITY;
  private long _accessedExpireTimeoutWindow = -1;

  private long _localExpireTimeout
    = Alarm.isTest() ? -1 : 250L; // 250ms default timeout, except for QA

  private long _leaseExpireTimeout = 5 * 60 * 1000; // 5 min lease timeout

  private AbstractCache.Scope _scope = Scope.CLUSTER;
  
  private CacheLoader _cacheLoader;

  private CacheSerializer _keySerializer;
  private CacheSerializer _valueSerializer;

  private CacheEngine _engine;

  /**
   * The Cache will use a CacheLoader to populate cache misses.
   */

  public CacheLoader getCacheLoader()
  {
    return _cacheLoader;
  }

  /**
   * Sets the CacheLoader that the Cache can then use to
   * populate cache misses for a reference store (database)
   */
  public void setCacheLoader(CacheLoader cacheLoader)
  {
    _cacheLoader = cacheLoader;
  }

  /**
   * Returns the globally-unique id for the cache.
   */
  public String getGuid()
  {
    return _guid;
  }

  /**
   * Sets the globally-unique id for the cache
   */
  public void setGuid(String guid)
  {
    _guid = guid;
  }


  /**
   * Returns the globally-unique id for the cache.
   */
  public HashKey getCacheKey()
  {
    return _cacheKey;
  }

  /**
   * Sets the globally-unique id for the cache
   */
  public void setCacheKey(HashKey cacheKey)
  {
    _cacheKey = cacheKey;
  }

  /**
   * Returns internal flags
   */
  public int getFlags()
  {
    return _flags;
  }

  /**
   * Sets internal flags
   */
  public void setFlags(int flags)
  {
    _flags = flags;
  }

  /**
   * The maximum valid time for an item after a modification.
   * Items stored in the cache for longer than the expire time
   * are no longer valid and will return null from a get.
   *
   * Default is infinite.
   */
  public long getModifiedExpireTimeout()
  {
    return _modifiedExpireTimeout;
  }

  /**
   * The maximum valid time for an item.  Items stored in the cache
   * for longer than the expire time are no longer valid and will
   * return null from a get.
   *
   * Default is infinite.
   */
  @Configurable
  public void setModifiedExpireTimeout(long expireTimeout)
  {
    if (expireTimeout < 0 || TIME_INFINITY <= expireTimeout)
      expireTimeout = TIME_INFINITY;

    _modifiedExpireTimeout = expireTimeout;
  }
  
  /**
   * Returns the expire check window, i.e. the precision of the expire
   * check.  Since an expired item can cause a massive cascade of
   * attempted loads from the backup, the actual expiration is randomized.
   */
  public long getModifiedExpireTimeoutWindow()
  {
    return (_modifiedExpireTimeoutWindow > 0
            ? _modifiedExpireTimeoutWindow
            : _modifiedExpireTimeout / 4);
  }

  /**
   * Provides the opportunity to control the expire check window,
   * i.e. the precision of the expirecheck.
   * <p/>
   * Since an expired item can cause a massive cascade of
   * attempted loads from the backup, the actual expiration is randomized.
   */
  @Configurable
  public void setModifiedExpireTimeoutWindow(long expireTimeoutWindow)
  {
    _modifiedExpireTimeoutWindow = expireTimeoutWindow;
  }

  /**
   * The maximum time that an item can remain in cache without being referenced.
   * For example, session data could be configured to be removed if idle for more than 30 minutes.
   * <p/>
   * Cached data would typically have infinite idle time because
   * it doesn't depend on how often it's accessed.
   *
   * Default is infinite.
   */
  public long getAccessedExpireTimeout()
  {
    return _accessedExpireTimeout;
  }

  /**
   * The maximum time that an item can remain in cache without being referenced.
   * For example, session data could be configured to be removed if idle for more than 30 minutes.
   *
   * Cached data would typically use an infinite idle time because
   * it doesn't depend on how often it's accessed.
   */
  public void setAccessedExpireTimeout(long timeout)
  {
    if (timeout < 0 || TIME_INFINITY <= timeout)
      timeout = TIME_INFINITY;

    _accessedExpireTimeout = timeout;
  }
  
  /**
   * Returns the idle check window, i.e. the precision of the idle
   * check.
   */
  public long getAccessedExpireTimeoutWindow()
  {
    return (_accessedExpireTimeoutWindow > 0
            ? _accessedExpireTimeoutWindow
            : _accessedExpireTimeout / 4);
  }

  /**
   * Provides the option to set the idle check window,  the amount of time
   * in which the idle time limit can be spread out to smooth performance.
   * <p/>
   * If this optional value is not set, the system  uses a fraction of the
   * idle time.
   */
  public void setAccessedExpireTimeoutWindow(long idleTimeoutWindow)
  {
    _accessedExpireTimeoutWindow = idleTimeoutWindow;
  }

  /**
   * Returns the lease timeout, which is the time a server can use the local version
   * if it owns it, before a timeout.
   */
  public long getLeaseExpireTimeout()
  {
    return _leaseExpireTimeout;
  }

  /**
   * The lease timeout is the time a server can use the local version
   * if it owns it, before a timeout.
   */
  public void setLeaseExpireTimeout(long timeout)
  {
    _leaseExpireTimeout = timeout;
  }

  /**
   * The local read timeout is the time a local copy of the
   * cache is considered valid without checking the backing store.
   */
  public long getLocalExpireTimeout()
  {
    return _localExpireTimeout;
  }

  /**
   * The local expire time is the time a local copy of the
   * cache is considered valid.
   */
  public void setLocalExpireTimeout(long timeout)
  {
    _localExpireTimeout = timeout;
  }
  
  /**
   * Returns true if all gets are synchronous, i.e. must be checked with
   * the owning server on each request.
   */
  public boolean isSynchronousGet()
  {
    return getLocalExpireTimeout() <= 0;
  }

  /**
   * Returns the key serializer
   */
  public CacheSerializer getKeySerializer()
  {
    return _keySerializer;
  }

  /**
   * Returns the value serializer
   */
  public CacheSerializer getValueSerializer()
  {
    return _valueSerializer;
  }

  /**
   * Sets the value serializer
   */
  public void setValueSerializer(CacheSerializer serializer)
  {
    _valueSerializer = serializer;
  }

  public boolean isBackup()
  {
    return (getFlags() & CacheConfig.FLAG_BACKUP) != 0;
  }
  
  public static boolean isBackup(int flags)
  {
    return (flags & CacheConfig.FLAG_BACKUP) != 0;
  }

  /**
   * Sets the backup mode.  If backups are enabled, copies of the
   * cache item will be sent to the owning triad server.
   * <p/>
   * Defaults to true.
   */
  private void setBackup(boolean isBackup)
  {
    if (isBackup)
      setFlags(getFlags() | CacheConfig.FLAG_BACKUP);
    else
      setFlags(getFlags() & ~CacheConfig.FLAG_BACKUP);
  }

  /**
   * Sets the global mode.  If global is enabled, copies of the
   * cache item will be sent to all clusters.
   * <p/>
   * Defaults to false.
   */
  public boolean isGlobal()
  {
    return (getFlags() & CacheConfig.FLAG_GLOBAL) != 0;
  }
  
  public static boolean isGlobal(int flags)
  {
    return (flags & CacheConfig.FLAG_GLOBAL) != 0;
  }

  /**
   * Sets the global mode.  If global is enabled, copies of the
   * cache item will be sent to all clusters.
   * <p/>
   * Defaults to false.
   */
  public void setGlobal(boolean isGlobal)
  {
    if (isGlobal)
      setFlags(getFlags() | CacheConfig.FLAG_GLOBAL);
    else
      setFlags(getFlags() & ~CacheConfig.FLAG_GLOBAL);
  }

  /**
   * Returns true is the triplicate backup mode enabled so that
   * all triad servers have a copy of the cache item.
   * <p/>
   * Defaults is true.
   */
  public boolean isTriplicate()
  {
    return (getFlags() & CacheConfig.FLAG_TRIPLICATE) != 0;
  }
  
  public static boolean isTriplicate(int flags)
  {
    return (flags & CacheConfig.FLAG_TRIPLICATE) != 0;
  }

  /**
   * Sets the transient mode.
   */
  private void setTransient(boolean isTransient)
  {
    if (isTransient)
      setFlags(getFlags() | CacheConfig.FLAG_TRANSIENT);
    else
      setFlags(getFlags() & ~CacheConfig.FLAG_TRANSIENT);
  }

  /**
   * Sets the triplicate backup mode.  If triplicate backups is set,
   * all triad servers have a copy of each cached item.
   * <p/>
   * Defaults to true.
   */
  private void setTriplicate(boolean isTriplicate)
  {
    if (isTriplicate)
      setFlags(getFlags() | CacheConfig.FLAG_TRIPLICATE);
    else
      setFlags(getFlags() & ~CacheConfig.FLAG_TRIPLICATE);
  }

  /**
   * Sets the {@link AbstractCache.Scope} of this cache.
   */
  public void setScopeMode(AbstractCache.Scope scope)
  {
    _scope = scope;
  }

  /**
   * Returns the {@link AbstractCache.Scope} defined for this cache.
   * @return
   */
  public AbstractCache.Scope getScopeMode()
  {
    return _scope;
  }
  
  public void setEngine(CacheEngine engine)
  {
    if (engine == null)
      throw new NullPointerException();
    
    _engine = engine;
  }
  
  public CacheEngine getEngine()
  {
    return _engine;
  }

  /**
   * Initializes the CacheConfig.
   */
  public void init()
  {
    if (_keySerializer == null)
      _keySerializer = new HessianSerializer();

    if (_valueSerializer == null)
      _valueSerializer = new HessianSerializer();

    switch (_scope) {
    case TRANSIENT:
      setTransient(true);
      setTriplicate(false);
      setBackup(false);
      if (getEngine() == null)
        setEngine(new AbstractCacheEngine());
      break;
      
    case LOCAL:
      setTriplicate(false);
      setBackup(false);
      if (getEngine() == null)
        setEngine(new AbstractCacheEngine());
      break;
      
    case CLUSTER:
      setTriplicate(true);
      setBackup(true);
      break;
      
      /*
    case CLUSTER_SINGLE:
      setTriplicate(false);
      setBackup(false);
      break;
      
    case CLUSTER_BACKUP:
      setTriplicate(false);
      setBackup(true);
      break;
      */
    }
    // _accuracy = CacheStatistics.STATISTICS_ACCURACY_BEST_EFFORT;
  }

  @Override
  public String toString()
  {
    return getClass().getSimpleName() + "[]";
  }
}
