Package com.caucho.distcache

Source Code of com.caucho.distcache.AbstractCache$CacheKeys

/*
* 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.distcache;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.annotation.PostConstruct;
import javax.cache.CacheEntry;
import javax.cache.CacheListener;
import javax.cache.CacheLoader;
import javax.cache.CacheStatistics;

import com.caucho.config.ConfigException;
import com.caucho.config.Configurable;
import com.caucho.config.types.Period;
import com.caucho.env.distcache.CacheDataBacking;
import com.caucho.env.distcache.DistCacheSystem;
import com.caucho.loader.Environment;
import com.caucho.server.distcache.AbstractCacheManager;
import com.caucho.server.distcache.CacheConfig;
import com.caucho.server.distcache.DataStore;
import com.caucho.server.distcache.DistCacheEntry;
import com.caucho.server.distcache.DistributedCacheManager;
import com.caucho.server.distcache.MnodeStore;
import com.caucho.util.HashKey;
import com.caucho.util.L10N;
import com.caucho.util.LruCache;
import com.caucho.vfs.StreamSource;
import com.caucho.vfs.WriteStream;

/**
* Implements the distributed cache
*/

abstract public class AbstractCache extends AbstractMap
  implements ObjectCache, ByteStreamCache, CacheStatistics, Closeable
{
  private static final L10N L = new L10N(AbstractCache.class);

  private CacheManagerImpl _localManager;
  private DistributedCacheManager _manager;

  private String _name = null;

  private String _guid;

  private Collection<CacheListener> _listeners
    = new ConcurrentLinkedQueue<CacheListener>();

  private CacheConfig _config = new CacheConfig();

  private LruCache<Object,DistCacheEntry> _entryCache;

  private boolean _isInit;
  private boolean _isClosed;

  private long _priorMisses = 0;
  private long _priorHits = 0;

  private String _scopeName = Scope.CLUSTER.toString();
  private String _persistenceOption = Persistence.TRIPLE.toString();

  public AbstractCache()
  {
  }

  /**
   * Returns the name of the cache.
   */
  public String getName()
  {
    return _name;
  }

  /**
   * Assigns the name of the cache.
   * A name is mandatory and must be unique among open caches.
   */
  @Configurable
  public void setName(String name)
  {
    _name = name;
  }

  public void setGuid(String guid)
  {
    _guid = guid;
  }
 
  public String getGuid()
  {
    return _guid;
  }

  /**
   * Sets the CacheLoader that the Cache can then use to populate
   * cache misses from a reference store (database).
   */
  @Configurable
  public void setCacheLoader(CacheLoader loader)
  {
    _config.setCacheLoader(loader);
  }

  /**
   * Assign the serializer used on values.
   *
   * @Note: This setting should not be changed after
   * a cache is created.
   */
  @Configurable
  public void setSerializer(CacheSerializer serializer)
  {
    _config.setValueSerializer(serializer);
  }

  /**
   * 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.
   */
  @Configurable
  public void setBackup(boolean isBackup)
  {
    _config.setBackup(isBackup);
  }

  /**
   * Sets the global mode.  If global is enabled, copies of the
   * cache item will be sent to all clusters
   * <p/>
   * Defaults to false.
   */
  @Configurable
  public void setGlobal(boolean isGlobal)
  {
    _config.setGlobal(isGlobal);
  }

  /**
   * Sets the triplicate backup mode.  If triplicate backups is set,
   * all triad servers have a copy of the cache item.
   * <p/>
   * Defaults to true.
   */
  @Configurable
  public void setTriplicate(boolean isTriplicate)
  {
    _config.setTriplicate(isTriplicate);
  }

  /**
   * The maximum valid time for an item.  Items stored in the cache
   * for longer than the expire time are no longer valid and z null value
   * will be returned for a get.
   * <p/>
   * Default is infinite.
   */
  public long getExpireTimeout()
  {
    return _config.getExpireTimeout();
  }

  /**
   * The maximum valid time for a cached item before it expires.
   * Items stored in the cache for longer than the expire time are
   * no longer valid and will return null from a get.
   * <p/>
   * Default is infinite.
   */
  @Configurable
  public void setExpireTimeout(Period expireTimeout)
  {
    setExpireTimeoutMillis(expireTimeout.getPeriod());
  }

  /**
   * 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.
   * <p/>
   * Default is infinite.
   */
  @Configurable
  public void setExpireTimeoutMillis(long expireTimeout)
  {
    _config.setExpireTimeout(expireTimeout);
  }

  /**
   * The maximum idle time for an item, which is typically used for
   * temporary data like sessions.  For example, session
   * data might be removed if idle over 30 minutes.
   * <p/>
   * Cached data would have infinite idle time because
   * it doesn't depend on how often it's accessed.
   * <p/>
   * Default is infinite.
   */
  @Configurable
  public void setIdleTimeout(Period period)
  {
    setIdleTimeoutMillis(period.getPeriod());
  }

  /**
   * The maximum idle time for an item, which is typically used for
   * temporary data like sessions.  For example, session
   * data might be removed if idle over 30 minutes.
   * <p/>
   * Cached data would have infinite idle time because
   * it doesn't depend on how often it's accessed.
   * <p/>
   * Default is infinite.
   */
  public long getIdleTimeout()
  {
    return _config.getIdleTimeout();
  }

  /**
   * Sets the idle timeout in milliseconds
   */
  @Configurable
  public void setIdleTimeoutMillis(long timeout)
  {
    _config.setIdleTimeout(timeout);
  }

  /**
   * Returns the idle check window, used to minimize traffic when
   * updating access times.
   */
  public long getIdleTimeoutWindow()
  {
    return _config.getIdleTimeoutWindow();
  }

  /**
   * Sets the idle timeout windows
   */
  public void setIdleTimeoutWindow(Period period)
  {
    _config.setIdleTimeoutWindow(period.getPeriod());
  }

  /**
   * The lease timeout is the time a server can use the local version
   * if it owns it, before a timeout.
   */
  public long getLeaseTimeout()
  {
    return _config.getLeaseTimeout();
  }

  /**
   * The lease timeout is the time a server can use the local version
   * if it owns it, before a timeout.
   */
  @Configurable
  public void setLeaseTimeout(Period period)
  {
    setLeaseTimeoutMillis(period.getPeriod());
  }

  /**
   * The lease timeout is the time a server can use the local version
   * if it owns it, before a timeout.
   */
  @Configurable
  public void setLeaseTimeoutMillis(long timeout)
  {
    _config.setLeaseTimeout(timeout);
  }

  /**
   * The local read timeout is how long a local copy of
   * a cache item can be reused before checking with the master copy.
   * <p/>
   * A read-only item could be infinite (-1).  A slow changing item
   * like a list of bulletin-board comments could be 10s.  Even a relatively
   * quickly changing item can be 10ms or 100ms.
   * <p/>
   * The default is 10ms
   */
  public long getLocalReadTimeout()
  {
    return _config.getLocalReadTimeout();
  }

  /**
   * The local read timeout sets how long a local copy of
   * a cache item can be reused before checking with the master copy.
   * <p/>
   * A read-only item could be infinite (-1).  A slow changing item
   * like a list of bulletin-board comments could be 10s.  Even a relatively
   * quicky changing item can be 10ms or 100ms.
   * <p/>
   * The default is 10ms
   */
  @Configurable
  public void setLocalReadTimeout(Period period)
  {
    setLocalReadTimeoutMillis(period.getPeriod());
  }

  /**
   * The local read timeout sets how long a local copy of
   * a cache item can be reused before checking with the master copy.
   * <p/>
   * A read-only item could be infinite (-1).  A slow changing item
   * like a list of bulletin-board comments could be 10s.  Even a relatively
   * quicky changing item can be 10ms or 100ms.
   * <p/>
   * The default is 10ms
   */
  @Configurable
  public void setLocalReadTimeoutMillis(long period)
  {
    _config.setLocalReadTimeout(period);
  }

  public void setScopeMode(Scope scope)
  {
    _config.setScopeMode(scope);
  }

  /**
   * Sets the {@link Scope} of the cache.
   */
  @Configurable
  public void setScope(String scopeName)
  {
    _scopeName = scopeName;
  }

  /**
   * Returns the name of the Scope of the cache.
   * @return
   */
  public String getScope()
  {
    return _config.getScopeMode().toString().toLowerCase(Locale.ENGLISH);
  }

  public void setPersistence(String persistenceOption)
  {
    _persistenceOption = persistenceOption;
  }
 
  public void setCacheManager(CacheManagerImpl cacheManager)
  {
    if (_localManager != null && _localManager != cacheManager)
      throw new IllegalStateException();
   
    _localManager = cacheManager;
  }

  public static AbstractCache getMatchingCache(String name)
  {
    DistCacheSystem cacheService = DistCacheSystem.getCurrent();
   
    CacheManagerImpl localManager = cacheService.getCacheManager();

    String contextId = Environment.getEnvironmentName();

    String guid = contextId + ":" + name;
 
    return localManager.get(guid);
  }

  /**
   * Initialize the cache.
   */
  @PostConstruct
  public void init()
  {
    init(false);
  }
 
  public AbstractCache createIfAbsent()
  {
    init(true);
   
    return _localManager.get(_guid);
  }
 
 

  private void init(boolean ifAbsent)
  {
    synchronized (this) {
      if (_isInit)
        return;

      _isInit = true;

      _config.init();

      initServer();

      initName(_name);

      initScope(_scopeName);

      initPersistence(_persistenceOption);

      _config.setCacheKey(_manager.createSelfHashKey(_config.getGuid(),
                                                     _config.getKeySerializer()));

      if (_localManager == null) {
        DistCacheSystem cacheService = DistCacheSystem.getCurrent();
       
        _localManager = cacheService.getCacheManager();
      }
     
      if (_localManager.putIfAbsent(_guid, this) != null) {
        if (ifAbsent) {
          close();
          return;
        }
       
        throw new ConfigException(L.l("'{0}' with full name '{1}' is an invalid Cache name because it's already used by another cache.",
                                      this, _guid));
      }

      _entryCache = new LruCache<Object,DistCacheEntry>(512);
     
      Environment.addCloseListener(this);
    }
   
    _manager.initCache(this);
  }

  /**
   * Returns the object with the given key without checking the backing store.
   */
  @Override
  public Object peek(Object key)
  {
    DistCacheEntry cacheEntry = _entryCache.get(key);

    return (cacheEntry != null) ? cacheEntry.peek() : null;
  }
 
  /**
   * Returns the hash of the given key
   */
  public HashKey getKeyHash(Object key)
  {
    return getDistCacheEntry(key).getKeyHash();
  }

  /**
   * Returns the object with the given key, checking the backing
   * store if necessary.
   */
  @Override
  public Object get(Object key)
  {
    return getDistCacheEntry(key).get(_config);
  }

  /**
   * Returns the object with the given key, updating the backing
   * store if necessary.
   */
  /*
  @Override
  public Object getLazy(Object key)
  {
    return getDistCacheEntry(key).getLazy(_config);
  }
  */

  /**
   * Fills an output stream with the value for a key.
   */
  @Override
  public boolean get(Object key, OutputStream os)
    throws IOException
  {
    return getDistCacheEntry(key).getStream(os, _config);
  }

  /**
   * Returns the cache entry for the object with the given key.
   */
  @Override
  public ExtCacheEntry getExtCacheEntry(Object key)
  {
    return getDistCacheEntry(key).getMnodeValue(_config);
  }
 
  public ExtCacheEntry getExtCacheEntry(HashKey key)
  {
    return getDistCacheEntry(key).getMnodeValue(_config);
  }

  /**
   * Returns the cache entry for the object with the given key.
   */
  @Override
  public ExtCacheEntry peekExtCacheEntry(Object key)
  {
    return getDistCacheEntry(key).getMnodeValue();
  }
 
  public ExtCacheEntry getStatCacheEntry(Object key)
  {
    return getDistCacheEntry(key);
  }

  /**
   * Returns the cache entry for the object with the given key.
   */
  @Override
  public CacheEntry getCacheEntry(Object key)
  {
    return getExtCacheEntry(key);
  }

  /**
   * Puts a new item in the cache.
   *
   * @param key   the key of the item to put
   * @param value the value of the item to put
   */
  @Override
  public Object put(Object key, Object value)
  {
    Object object = getDistCacheEntry(key).put(value, _config);
    notifyPut(key);

    return object;
  }

  /**
   * Puts a new item in the cache with a custom idle
   * timeout (used for sessions).
   *
   * @param key         the key of the item to put
   * @param is          the value of the item to put
   * @param idleTimeout the idle timeout for the item
   */
  @Override
  public ExtCacheEntry put(Object key,
                           InputStream is,
                           long idleTimeout)
    throws IOException
  {
    return getDistCacheEntry(key).put(is, _config, idleTimeout);
  }

  /**
   * Updates the cache if the old version matches the current version.
   * A zero value for the old value hash only adds the entry if it's new.
   *
   * @param key     the key to compare
   * @param version the version of the old value, returned by getEntry
   * @param value   the new value
   * @return true if the update succeeds, false if it fails
   */
  @Override
  public boolean compareAndPut(Object key,
                               long version,
                               Object value)
  {
    put(key, value);

    return true;
  }

  /**
   * Updates the cache if the old version matches the current value.
   * A zero value for the old version only adds the entry if it's new.
   *
   * @param key         the key to compare
   * @param version     the hash of the old version, returned by getEntry
   * @param inputStream the new value
   * @return true if the update succeeds, false if it fails
   */
  @Override
  public boolean compareAndPut(Object key,
                               long version,
                               InputStream inputStream)
    throws IOException
  {
    put(key, inputStream);

    return true;
  }

  public void compareAndPut(HashKey key, HashKey value, long version)
  {
    getDistCacheEntry(key).compareAndPut(version, value, _config);
   
    notifyPut(key);
  }

  /**
   * Removes the entry from the cache.
   *
   * @return true if the object existed
   */
  @Override
  public Object remove(Object key)
  {
    notifyRemove(key);
   
    return getDistCacheEntry(key).remove(_config);
  }

  /**
   * Removes the entry from the cache if the current entry matches the version.
   */
  @Override
  public boolean compareAndRemove(Object key, long version)
  {
    DistCacheEntry cacheEntry = getDistCacheEntry(key);

    if (cacheEntry.getVersion() == version) {
      remove(key);

      return true;
    }

    return false;
  }
 
  /**
   * Returns the entry for the given key, returning the live item.
   */
  public ExtCacheEntry getLiveCacheEntry(Object key)
  {
    return getDistCacheEntry(key);
  }

  /**
   * Returns the CacheKeyEntry for the given key.
   */
  protected DistCacheEntry getDistCacheEntry(Object key)
  {
    DistCacheEntry cacheEntry = _entryCache.get(key);

    if (cacheEntry == null) {
      cacheEntry = _manager.getCacheEntry(key, _config);

      _entryCache.put(key, cacheEntry);
    }

    return cacheEntry;
  }

  /**
   * Returns the CacheKeyEntry for the given key.
   */
  protected DistCacheEntry getDistCacheEntry(HashKey key)
  {
    return _manager.getCacheEntry(key, _config);
  }

  /**
   * Returns a set containing an entry for each key->value pair in the local cache.
   */
  public Set<Map.Entry> entrySet()
  {
    return new CacheEntrySet<Entry>(_entryCache);
  }

  /**
   * Returns a new map of the items found in the central cache.
   *
   * @note If a cacheLoader is configured if an item is not found in the cache.
   */
  public Map getAll(Collection keys)
  {
    Map result = new HashMap();

    for (Object key : keys) {
      Object value = get(key);

      if (value != null) {
        result.put(key, value);
      }
    }

    return result;
  }

  /**
   * Loads an item into the cache if not already there and was returned from  in the optional cache loader.
   *
   * @param key
   */
  @Override
  public void load(Object key)
  {
    if (containsKey(key) || get(key) != null)
      return;

    Object loaderValue = cacheLoader(key);

    if (loaderValue != null)
      put(key, loaderValue);

    notifyLoad(key);
  }

  /**
   * Implements the loadAll method for a collection of keys.
   */
  public void loadAll(Collection keys)
  {
    Map<Object, Object> entries = null;
    CacheLoader loader = _config.getCacheLoader();

    if (loader == null || keys == null || keys.size() == 0)
      return;

    entries = loader.loadAll(keys);

    if (entries.isEmpty())
      return;

    for (Entry loaderEntry : entries.entrySet()) {
      Object loaderKey = loaderEntry.getKey();
      if (!containsKey(loaderKey) && (get(loaderKey) != null)) {
        put(loaderKey, loaderEntry.getValue());
        notifyLoad(loaderKey);
      }
    }
  }

  /**
   * Adds a listener to the cache.
   */
  @Override
  public void addListener(CacheListener listener)
  {
    _listeners.add(listener);
  }

  /**
   * Removes a listener from the cache.
   */
  @Override
  public void removeListener(CacheListener listener)
  {
    _listeners.remove(listener);
  }

  /**
   * Returns the CacheStatistics for this cache.
   */
  @Override
  public CacheStatistics getCacheStatistics()
  {
    return this;
  }

  /**
   * Ignored, since evictions are handled by the container.
   */
  @Override
  public void evict()
  {
    notifyEvict(null);
  }

  /**
   * Returns a collection of the values in the local cache.
   */
  public Collection values()
  {
    return new CacheValues(_entryCache);
  }

  /**
   * Returns a set of the keys in the local set.
   */
  public Set keySet()
  {
    return new CacheKeys(_entryCache);
  }

  /**
   * Returns true if the value is contained in the local cache.
   */
  @Override
  public boolean containsValue(Object value)
  {
    if (value == null)
      return false;

    Collection values = values();

    for (Object item : values) {
      if (value.equals(item))
        return true;
    }

    return false;
  }

  /**
   * Removes all items from the local cache.
   */
  @Override
  public void clear()
  {
    _entryCache.clear();
    notifyClear(null);
  }

  /**
   * Returns the number current size of the cache.
   */
  @Override
  public int size()
  {
    return _entryCache.size();
  }

  /**
   * Puts each item in the map into the cache.
   */
  @Override
  public void putAll(Map map)
  {
    if (map == null || map.size() == 0)
      return;
    Set entries = map.entrySet();

    for (Object item : entries) {
      Map.Entry entry = (Map.Entry) item;
      put(entry.getKey(), entry.getValue());
    }
  }

  /**
   * Returns true if an entry for the item is found in  the cache.
   *
   * @param key
   * @return
   */
  @Override
  public boolean containsKey(Object key)
  {
    return _entryCache.get(key) != null;
  }

  /**
   * Returns true is the local cache is empty
   *
   * @return
   */
  @Override
  public boolean isEmpty()
  {
    return _entryCache.size() == 0;
  }

  /**
   * Returns the number of cache hits that have occured since the cache started or
   * since the last call to clearStatistics.
   */
  @Override
  public int getCacheHits()
  {
    return (int) (_entryCache.getHitCount() - _priorHits);
  }

  /**
   * Returns the number of cache misses that have occured since the cache started or
   * since the last call to clearStatistics.
   */
  @Override
  public int getCacheMisses()
  {
    return (int) (_entryCache.getMissCount() - _priorMisses);
  }

  /**
   * Returns the number of entries currently in the local cache.
   */
  @Override
  public int getObjectCount()
  {
    return _entryCache.size();
  }

  /**
   * Simulates a reset of the counters for cache hits and misses.
   */
  @Override
  public void clearStatistics()
  {
    _priorHits = _entryCache.getHitCount();
    _priorMisses = _entryCache.getMissCount();
  }

  /**
   * Defines the accuracy of this implementation.
   */
  @Override
  public int getStatisticsAccuracy()
  {
    return CacheStatistics.STATISTICS_ACCURACY_BEST_EFFORT;
  }

  public boolean isBackup()
  {
    return _config.isBackup();
  }

  public boolean isTriplicate()
  {
    return _config.isTriplicate();
  }
 
  public HashKey getCacheKey()
  {
    return _config.getCacheKey();
  }

  /**
   * Places an item in the cache from the loader unless the item is in cache already.
   */
  protected Object cacheLoader(Object key)
  {
    Object value = get(key);

    if (value != null)
      return value;

    CacheLoader loader = _config.getCacheLoader();

    value = (loader != null) ? loader.load(key) : null;

    if (value != null)
      put(key, value);
    notifyLoad(key);

    return value;
  }

  protected  void setPersistenceMode(Persistence persistence)
  {
      switch (persistence) {
      case NONE:
        setTriplicate(false);
        setBackup(false);
        break;

      case SINGLE:
        setTriplicate(false);
        setBackup(true);
        break;

      case TRIPLE:
      default:
        setTriplicate(true);
    }
  }

  protected void notifyLoad(Object key)
  {
    for (CacheListener listener : _listeners) {
      listener.onLoad(key);
    }
  }

  protected void notifyEvict(Object key)
  {
    for (CacheListener listener : _listeners) {
      listener.onEvict(key);
    }
  }

  protected void notifyClear(Object key)
  {
    for (CacheListener listener : _listeners) {
      listener.onClear();
    }
  }

  protected void notifyPut(Object key)
  {
    for (CacheListener listener : _listeners) {
      listener.onPut(key);
    }
  }

  protected void notifyRemove(Object key)
  {
    for (CacheListener listener : _listeners) {
      listener.onRemove(key);
    }
  }

  @Override
  public boolean isClosed()
  {
    return _isClosed;
  }

  @Override
  public void close()
  {
    _isClosed = true;
   
    _localManager.remove(_guid);
  }

  private void initName(String name)
    throws ConfigException
  {
    if (_name == null || _name.length() == 0)
      throw new ConfigException(L.l("Each Cache must have a name."));

    String contextId = Environment.getEnvironmentName();

    if (_guid == null)
      _guid = contextId + ":" + _name;

    _config.setGuid(_guid);
  }

  private void initPersistence(String persistence)
    throws ConfigException
  {
    Persistence result  = Persistence.TRIPLE;

    if (persistence != null) {
      try {
        result = Persistence.valueOf(persistence.toUpperCase(Locale.ENGLISH));
      }
      catch (Exception e) {
        throw new ConfigException(L.l("'{0}' is not a valid Persistence option", persistence));
      }
    }

    setPersistenceMode(result);
  }
 
  public boolean loadData(HashKey valueHash, WriteStream os)
    throws IOException
  {
    return getDataBacking().loadData(valueHash, os);
  }

  public boolean saveData(HashKey valueHash, StreamSource source, int length)
    throws IOException
  {
    return getDataBacking().saveData(valueHash, source, length);
  }

  public boolean isDataAvailable(HashKey valueKey)
  {
    return getDataBacking().isDataAvailable(valueKey);
  }
 
  private CacheDataBacking getDataBacking()
  {
    return _manager.getDataBacking();
  }

  //
  // QA
  //
 
  public byte []getKeyHash(String name)
  {
    return getDistCacheEntry(name).getKeyHash().getHash();
  }
 
  public byte []getValueHash(Object value)
  {
    return _manager.calculateValueHash(value, _config);
  }
 
  @SuppressWarnings("unchecked")
  public MnodeStore getMnodeStore()
  {
    return ((AbstractCacheManager) _manager).getMnodeStore();
  }
 
  @SuppressWarnings("unchecked")
  public DataStore getDataStore()
  {
    return ((AbstractCacheManager) _manager).getDataStore();
  }
 
  public void saveData(Object value)
  {
    ((AbstractCacheManager) _manager).writeData(null, value,
                                                _config.getValueSerializer());
  }

  private void initScope(String scopeName)
    throws ConfigException
  {
    Scope scope = null;

    if (_scopeName != null) {
      try {
        scope = Scope.valueOf(_scopeName.toUpperCase(Locale.ENGLISH));
      }
      catch (Exception e) {
        throw new ConfigException(L.l("'{0}' is not a valid Scope option", scopeName));
      }
    }

    setScopeMode(scope);
  }

  public void setManager(DistributedCacheManager manager)
  {
    if (_manager != null)
      throw new IllegalStateException();
   
    _manager = manager;
  }
 
  private void initServer()
    throws ConfigException
  {
    if (_manager != null)
      return;
   
    DistCacheSystem cacheService = DistCacheSystem.getCurrent();

    if (cacheService == null)
      throw new ConfigException(L.l("'{0}' cannot be initialized because it is not in a clustered environment",
                                    getClass().getSimpleName()));

    _manager = cacheService.getDistCacheManager();

    if (_manager == null)
      throw new IllegalStateException("distributed cache manager not available");
  }


  /**
   * Defines the scope options for a cache.
   */
  public enum Scope {

    /** Not distributed, no persistence.*/
    LOCAL,

    /** Not distributed, single or no persistence */
    SERVER,

    /** Distributed across a pod, persistence required.*/
    POD,

    /** Accessible across a multi-pod cluster*/
    CLUSTER,

    /** Support CRUD operation with basic access control*/
    GLOBAL
  }

  /**
   * Defines the persistence options for a cache.
   */
  public enum Persistence {

    /**
     * No persistence.
     */
    NONE,

    /**
     * A single copy of the cache is persisted on one server in the cluster.
     */
    SINGLE,

    /**
     * Three copies of the cache and its entrys are saved on three servers.
     */
    TRIPLE
  }

  /**
   * provides the implementation of the set of entries over the
   * cache,
   */
  protected static class CacheEntrySet<E>
    extends AbstractSet
  {
    private LruCache<Object, CacheEntry> _lruCache;

    protected CacheEntrySet(LruCache cache)
    {
      super();
      _lruCache = cache;
    }

    public Iterator iterator()
    {
      return new CacheEntrySetIterator<Object,CacheEntry>(_lruCache);
    }

    public int size()
    {
      return _lruCache.size();
    }
  }

  /**
   * Provides an iterator over the entries in the the local cache.
   */
  protected static class CacheEntrySetIterator<K, V>
    implements Iterator
  {
    private Iterator<LruCache.Entry<K, V>> _iterator;

    protected CacheEntrySetIterator(LruCache<K, V> lruCache)
    {
      _iterator = lruCache.iterator();
    }

    public Object next()
    {
      if (!hasNext())
        throw new NoSuchElementException();

      LruCache.Entry<K, V> entry = _iterator.next();
      CacheEntry cacheEntry = (CacheEntry) entry.getValue();

      return new AbstractMap.SimpleEntry<Object, Object>(
        cacheEntry.getKey(),
        cacheEntry.getValue());
    }

    public boolean hasNext()
    {
      return _iterator.hasNext();
    }

    /**
     *
     */
    public void remove()
    {
      throw new UnsupportedOperationException(getClass().getName());
    }
  }

  /**
   * Provides the values contined in the local cache.
   */
  protected static class CacheValues<K,V>
    extends CacheEntrySet
  {
    private LruCache<K, V> _lruCache;

    public CacheValues(LruCache<K,V> lruCache)
    {
      super(lruCache);
      _lruCache = lruCache;
    }

    /**
     * Override the entry set iterator to return the value for the entry.
     *
     * @return
     */
    @Override
    public Iterator iterator()
    {
      return new CacheEntrySetIterator<K,V>(_lruCache) {
        @Override
        public Object next()
        {
          return ((Entry) super.next()).getValue();
        }
      };
    }
  }

  /**
   * Provides access to the keys of the map as a set.
   */
  protected static class CacheKeys
    extends CacheEntrySet
  {
    private LruCache _lruCache;

    public CacheKeys(LruCache cache)
    {
      super(cache);

      _lruCache = cache;
    }

    /**
     * Override the entry set iterator to return the key for the entry.
     */
    @Override
    public Iterator iterator()
    {
      return new CacheEntrySetIterator<Object, Object>(_lruCache) {
        @Override
        public Object next()
        {
          return ((Entry) super.next()).getKey();
        }
      };
    }
  }

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

Related Classes of com.caucho.distcache.AbstractCache$CacheKeys

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.