Package org.exoplatform.services.cache.impl

Source Code of org.exoplatform.services.cache.impl.CacheServiceImpl$FutureExoCacheCreationTask

/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.cache.impl;

import org.exoplatform.commons.utils.Tools;
import org.exoplatform.container.component.ComponentPlugin;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.management.annotations.ManagedBy;
import org.exoplatform.services.cache.CacheService;
import org.exoplatform.services.cache.ExoCache;
import org.exoplatform.services.cache.ExoCacheConfig;
import org.exoplatform.services.cache.ExoCacheConfigPlugin;
import org.exoplatform.services.cache.ExoCacheFactory;
import org.exoplatform.services.cache.ExoCacheInitException;
import org.exoplatform.services.cache.SimpleExoCache;
import org.exoplatform.services.cache.invalidation.InvalidationExoCache;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* Created by The eXo Platform SAS. Author : Tuan Nguyen
* tuan08@users.sourceforge.net Sat, Sep 13, 2003 @ Time: 1:12:22 PM
*/
@SuppressWarnings("deprecation")
@ManagedBy(CacheServiceManaged.class)
public class CacheServiceImpl implements CacheService
{
   /**
    * Logger.
    */
   private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.cache.CacheServiceImpl");

   private final ExoCacheFactory DEFAULT_FACTORY = new SimpleExoCacheFactory();

   private final HashMap<String, ExoCacheConfig> configs_ = new HashMap<String, ExoCacheConfig>();

   private final ConcurrentHashMap<String, FutureExoCacheCreationTask> cacheMap_ =
      new ConcurrentHashMap<String, FutureExoCacheCreationTask>();
  
   private final ExoCacheConfig defaultConfig_;

   private final LoggingCacheListener loggingListener_;

   private final ExoCacheFactory factory_;

   CacheServiceManaged managed;

   /**
    *
    */
   public CacheServiceImpl(InitParams params) throws Exception
   {
      this(params, null);
   }

   public CacheServiceImpl(InitParams params, ExoCacheFactory factory) throws Exception
   {
      List<ExoCacheConfig> configs = params.getObjectParamValues(ExoCacheConfig.class);
      for (ExoCacheConfig config : configs)
      {
         configs_.put(config.getName(), config);
      }
      defaultConfig_ = configs_.get("default");
      loggingListener_ = new LoggingCacheListener();
      factory_ = factory == null ? DEFAULT_FACTORY : factory;
   }

   public void addExoCacheConfig(ComponentPlugin plugin)
   {
      addExoCacheConfig((ExoCacheConfigPlugin)plugin);
   }

   public void addExoCacheConfig(ExoCacheConfigPlugin plugin)
   {
      List<ExoCacheConfig> configs = plugin.getConfigs();
      for (ExoCacheConfig config : configs)
      {
         configs_.put(config.getName(), config);
      }
   }

   @SuppressWarnings("unchecked")
   public <K extends Serializable, V> ExoCache<K, V> getCacheInstance(final String region)
   {
      if (region == null)
      {
         throw new IllegalArgumentException("region cannot be null");
      }
      if (region.length() == 0)
      {
         throw new IllegalArgumentException("region cannot be empty");
      }
      FutureExoCacheCreationTask creationTask = cacheMap_.get(region);
      if (creationTask == null)
      {
         Callable<ExoCache<? extends Serializable,?>> task = new Callable<ExoCache<? extends Serializable,?>>()
         {
            public ExoCache<? extends Serializable, ?> call() throws Exception
            {
               return createCacheInstance(region);
            }
         };
         creationTask = new FutureExoCacheCreationTask(task);
         FutureExoCacheCreationTask existingTask = cacheMap_.putIfAbsent(region, creationTask);
         if (existingTask != null)
         {
            creationTask = existingTask;
         }
         else
         {
            creationTask.run();
         }
      }
      try
      {
         return (ExoCache<K, V>)creationTask.get();
      }
      catch (CancellationException e)
      {
         cacheMap_.remove(region, creationTask);
      }
      catch (InterruptedException e)
      {
         Thread.currentThread().interrupt();
      }
      catch (ExecutionException e)
      {
         LOG.error("Could not create the cache for the region '" + region + "'", e.getCause());
      }
      return null;
   }

   @SuppressWarnings({"rawtypes", "unchecked"})
   private ExoCache<? extends Serializable, ?> createCacheInstance(String region) throws Exception
   {
      ExoCacheConfig config = configs_.get(region);
      if (config == null)
         config = defaultConfig_;

      // Ensure the configuration integrity
      final ExoCacheConfig safeConfig = config.clone();
      // Set the region as name
      safeConfig.setName(region);
     
      ExoCache simple = null;
      if (factory_ != DEFAULT_FACTORY && safeConfig.getClass().isAssignableFrom(ExoCacheConfig.class) //NOSONAR
         && safeConfig.getImplementation() != null)
      {
         // The implementation exists and the config is not a sub class of ExoCacheConfig
         // we assume that we expect to use the default cache factory
         try
         {
            // We check if the given implementation is a known class
            Class<?> implClass = Tools.loadClass(safeConfig.getImplementation(), this);
            // Implementation is an existing class
            if (ExoCache.class.isAssignableFrom(implClass))
            {
               // The implementation is a sub class of eXo Cache so we use the default factory
               simple = DEFAULT_FACTORY.createCache(safeConfig);              
            }
         }
         catch (ClassNotFoundException e)
         {
            if (LOG.isTraceEnabled())
            {
               LOG.trace("An exception occurred: " + e.getMessage());
            }
         }
      }
      if (simple == null)
      {
         // We use the configured cache factory
         simple = factory_.createCache(safeConfig);
      }
     
      if (managed != null)
      {
         managed.registerCache(simple);
      }
      // If the flag avoid value replication is enabled and the cache is replicated
      // or distributed we wrap the eXo cache instance into an InvalidationExoCache
      // to enable the invalidation
      return safeConfig.avoidValueReplication() && (safeConfig.isRepicated() || safeConfig.isDistributed())
         ? new InvalidationExoCache(simple) : simple;
   }

   public Collection<ExoCache<? extends Serializable, ?>> getAllCacheInstances()
   {
      Collection<ExoCache<? extends Serializable, ?>> caches =
         new ArrayList<ExoCache<? extends Serializable,?>>(cacheMap_.size());
      for (FutureTask<ExoCache<? extends Serializable,?>> task : cacheMap_.values())
      {
         ExoCache<? extends Serializable, ?> cache = null;
         try
         {
            cache = task.get();
         }
         catch (CancellationException e)
         {
            if (LOG.isTraceEnabled())
            {
               LOG.trace("An exception occurred: " + e.getMessage());
            }
         }
         catch (InterruptedException e)
         {
            if (LOG.isTraceEnabled())
            {
               LOG.trace("An exception occurred: " + e.getMessage());
            }
         }
         catch (ExecutionException e)
         {
            if (LOG.isTraceEnabled())
            {
               LOG.trace("An exception occurred: " + e.getMessage());
            }
         }
         if (cache != null)
         {
            caches.add(cache);           
         }
      }
      return caches;
   }

   /**
    * Default implementation of an {@link org.exoplatform.services.cache.ExoCacheFactory}
    */
   private class SimpleExoCacheFactory implements ExoCacheFactory
   {

      /**
       * {@inheritDoc}
       */
      @SuppressWarnings({"rawtypes", "unchecked"})
      public ExoCache createCache(ExoCacheConfig config) throws ExoCacheInitException
      {
         final ExoCache simple = createCacheInstance(config);
         simple.setName(config.getName());
         simple.setLabel(config.getLabel());
         simple.setMaxSize(config.getMaxSize());
         simple.setLiveTime(config.getLiveTime());
         simple.setLogEnabled(config.isLogEnabled());
         if (simple.isLogEnabled())
         {
            simple.addCacheListener(loggingListener_);
         }
         return simple;
      }

      /**
       * Create a new instance of ExoCache according to the given configuration
       * @param config the ExoCache configuration
       * @return a new instance of ExoCache
       * @throws ExoCacheInitException if any exception happens while initializing the cache
       */
      @SuppressWarnings("rawtypes")
      private ExoCache createCacheInstance(ExoCacheConfig config) throws ExoCacheInitException
      {
         if (config.getImplementation() == null)
         {
            // No implementation has been defined
            return new SimpleExoCache();
         }
         else
         {
            // An implementation has been defined
            try
            {
               final Class<?> clazz = Tools.loadClass(config.getImplementation(), this);
               return (ExoCache)clazz.newInstance();
            }
            catch (ExceptionInInitializerError e)
            {
               throw new ExoCacheInitException("Cannot create instance of ExoCache of type "
                  + config.getImplementation(), e);
            }
            catch (SecurityException e)
            {
               throw new ExoCacheInitException("Cannot create instance of ExoCache of type "
                  + config.getImplementation(), e);
            }
            catch (ClassNotFoundException e)
            {
               throw new ExoCacheInitException("Cannot create instance of ExoCache of type "
                  + config.getImplementation(), e);
            }
            catch (InstantiationException e)
            {
               throw new ExoCacheInitException("Cannot create instance of ExoCache of type "
                  + config.getImplementation(), e);
            }
            catch (IllegalAccessException e)
            {
               throw new ExoCacheInitException("Cannot create instance of ExoCache of type "
                  + config.getImplementation(), e);
            }
         }
      }
   }
  
   /**
    * This class is used to reduce the contention when the cache is already created
    */
   private static class FutureExoCacheCreationTask extends FutureTask<ExoCache<? extends Serializable, ?>>
   {

      private volatile ExoCache<? extends Serializable, ?> cache;
     
      /**
       * @param callable
       */
      public FutureExoCacheCreationTask(Callable<ExoCache<? extends Serializable, ?>> callable)
      {
         super(callable);
      }

      @Override
      public ExoCache<? extends Serializable, ?> get() throws InterruptedException, ExecutionException
      {
         if (cache != null)
         {
            return cache;
         }
         return cache = super.get();
      }
   }
}
TOP

Related Classes of org.exoplatform.services.cache.impl.CacheServiceImpl$FutureExoCacheCreationTask

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.