Package org.jboss.cache

Source Code of org.jboss.cache.UnitTestCacheFactory

/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.ConfigurationException;
import org.jboss.cache.config.parsing.XmlConfigurationParser;
import org.jboss.cache.config.parsing.XmlConfigurationParser2x;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.util.TestingUtil;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author <a href="mailto:dpospisi@redhat.com">Dominik Pospisil (dpospisi@redhat.com)</a>
*/
public class UnitTestCacheFactory<K, V> implements CacheFactory<K, V>
{

   private final Log log = LogFactory.getLog(UnitTestCacheFactory.class);


   /**
    * Holds unique mcast_addr for each thread used for JGroups channel construction.
    */
   private static final ThreadLocal<String> threadMcastIP = new ThreadLocal<String>()
   {
      private final AtomicInteger uniqueAddr = new AtomicInteger(11);

      @Override
      protected String initialValue()
      {
         return "228.10.10." + uniqueAddr.getAndIncrement();
      }
   };

   /**
    * Holds unique mcast_port for each thread used for JGroups channel construction.
    */
   private static final ThreadLocal<Integer> threadMcastPort = new ThreadLocal<Integer>()
   {
      private final AtomicInteger uniquePort = new AtomicInteger(45589);

      @Override
      protected Integer initialValue()
      {
         return uniquePort.getAndIncrement();
      }
   };

   /**
    * For each thread holds list of caches created using this factory.
    */
   private static final ThreadLocal<List<Cache>> threadCaches =
         new ThreadLocal<List<Cache>>()
         {
            @Override
            protected List<Cache> initialValue()
            {
               return new ArrayList<Cache>();
            }
         };

   private final static List<Cache> allCaches = new ArrayList<Cache>();

   /**
    * For each thread holds the name of the test class which executed createCache factory method.
    */
   private static final ThreadLocal<String> threadTestName = new ThreadLocal<String>();

   // factory methods

   public Cache<K, V> createCache() throws ConfigurationException
   {
      return createCache(true);
   }

   public Cache<K, V> createCache(boolean start) throws ConfigurationException
   {
      return createCache(new Configuration(), start);
   }

   public Cache<K, V> createCache(String configFileName) throws ConfigurationException
   {
      return createCache(configFileName, true);
   }

   public Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException
   {
      XmlConfigurationParser parser = new XmlConfigurationParser();
      Configuration c;
      try
      {
         c = parser.parseFile(configFileName);
      }
      catch (ConfigurationException e)
      {
         System.out.println("Detected legacy configuration file format when parsing [" + configFileName + "].  Migrating to the new (3.x) file format is recommended.  See FAQs for details.");
         XmlConfigurationParser2x oldParser = new XmlConfigurationParser2x();
         c = oldParser.parseFile(configFileName);
      }
      return createCache(c, start);
   }

   public Cache<K, V> createCache(Configuration configuration) throws ConfigurationException
   {
      return createCache(configuration, true);
   }

   public Cache<K, V> createCache(InputStream is) throws ConfigurationException
   {
      return createCache(is, true);
   }

   public Cache<K, V> createCache(InputStream is, boolean start) throws ConfigurationException
   {
      XmlConfigurationParser parser = new XmlConfigurationParser();
      Configuration c = parser.parseStream(is);
      return createCache(c, start);
   }

   public Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException
   {
      // - Do not print out this exception - since tests are ALSO run from IDEs on the main thread. - MANIK
//      if (!Thread.currentThread().getName().contains("pool"))
//      {
//         System.out.println("CreateCache called from wrong thread: " + Thread.currentThread().getName());
//      }

      checkCaches();

      switch (configuration.getCacheMode())
      {
         case LOCAL:
            // local cache, no channel used
            break;
         case REPL_SYNC:
         case REPL_ASYNC:
         case INVALIDATION_ASYNC:
         case INVALIDATION_SYNC:
            // replicated cache, update channel setup
            mangleConfiguration(configuration);
            break;
         default:
            log.info("Unknown cache mode!");
      }

      Cache<K, V> cache = new DefaultCacheFactory<K, V>().createCache(configuration, start);

      List<Cache> caches = threadCaches.get();
      caches.add(cache);

      synchronized (allCaches)
      {
         allCaches.add(cache);
      }
      return cache;

   }

   /**
    * Destroys all caches created by this factory in the current thread.
    *
    * @return true if some cleanup was actually performed
    */
   public boolean cleanUp()
   {
      List<Cache> caches = new ArrayList<Cache>(threadCaches.get());
      boolean ret = false;

      for (Cache cache : caches)
      {
         TestingUtil.killCaches(cache);
         ret = true;
      }
      return ret;
   }

   public void removeCache(Cache c)
   {

      // - Do not print out this exception - since tests are ALSO run from IDEs on the main thread. - MANIK
//      if (!Thread.currentThread().getName().contains("pool"))
//      {
//         System.out.println("RemoveCache called from wrong thread.");
//      }

      List<Cache> caches = threadCaches.get();
      synchronized (allCaches)
      {
         if (caches.contains(c))
         {
            caches.remove(c);
            allCaches.remove(c);
         }
         else if (allCaches.contains(c))
         {
            System.out.println("[" + Thread.currentThread().getName() + "] WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Remove cache called from different thread.");
            Thread.dumpStack();
         }
      }
   }

   /**
    * Updates cluster configuration to ensure mutual thread isolation.
    *
    * @param configuration Configuration to update.
    */
   public void mangleConfiguration(Configuration configuration)
   {

      configuration.setClusterConfig(mangleClusterConfiguration(configuration.getClusterConfig()));
      // Check if the cluster name contains thread id. If not, append.
      // We can not just append the threadId, since some of the tests are crating instances
      // using configurations derived from configurations returned by this factory.

      String clusterName = configuration.getClusterName();

      // append thread id
      if (clusterName.indexOf(Thread.currentThread().getName()) == -1)
      {
         clusterName = clusterName + "-" + Thread.currentThread().getName();
//       System.out.println(getThreadId() + " Setting cluster name " + newClusterName);        
      }

//      String testName = extractTestName();

      // prepend test name
      /*
      if (clusterName.indexOf(testName) == -1) {
         clusterName = testName + "-" + clusterName;
      }
      */

      configuration.setClusterName(clusterName);

   }

   /**
    * Updates cluster configuration to ensure mutual thread isolation.
    */
   public String mangleClusterConfiguration(String clusterConfig)
   {
      if (clusterConfig == null)
      {
         // No explicit cluster configuration found. we need to resolve the default config
         // now in orded to be able to update it before the cache (and the channel) starts.        

         // TODO: this does not seem to be the best solution :(
         clusterConfig = UnitTestCacheConfigurationFactory.getClusterConfigFromFile(
               new Configuration().getDefaultClusterConfig());

      }

      // - Do not print out this exception - since tests are ALSO run from IDEs on the main thread. - MANIK
//
//      if (Thread.currentThread().getName().equals("main")) {
//         Exception e = new Exception("Invoked from main thread.");
//         e.printStackTrace();
//      };

      // replace mcast_addr
      Pattern pattern = Pattern.compile("mcast_addr=[^;]*");
      Matcher m = pattern.matcher(clusterConfig);
      if (m.find())
      {
         String origAddr = m.group().substring(m.group().indexOf("=") + 1);
         String newAddr = threadMcastIP.get();
//         System.out.println(getThreadId() + " Replacing mcast_addr " + origAddr + " with " + newAddr);
         clusterConfig = m.replaceFirst("mcast_addr=" + newAddr);
      }
      else
      {
         Thread.dumpStack();
         System.exit(1);
      }

      // replace mcast_port
      pattern = Pattern.compile("mcast_port=[^;]*");
      m = pattern.matcher(clusterConfig);
      if (m.find())
      {
//         String origPort = m.group().substring(m.group().indexOf("=") + 1);
         String newPort = threadMcastPort.get().toString();
         //       System.out.println(getThreadId() + " Replacing mcast_port " + origPort + " with " + newPort);
         clusterConfig = m.replaceFirst("mcast_port=" + newPort);
      }

      return clusterConfig;
   }

//   private String getThreadId()
//   {
//      return "[" + Thread.currentThread().getName() + "]";
//   }

   private void checkCaches()
   {
      String lastTestName = threadTestName.get();
      String currentTestName = extractTestName();

      if ((lastTestName != null) && (!lastTestName.equals(currentTestName)))
      {

         String threadId = "[" + Thread.currentThread().getName() + "] ";

         // we are running new test class
         // check if there is a cache(s) instance left & kill it if possitive

         if (cleanUp())
         {
            System.out.print(threadId + "WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
            System.out.print(threadId + " A test method in " + lastTestName + " did not clean all cache instances properly. ");
            System.out.println(threadId + " Use UnitTestCacheFactory.cleanUp() or TestngUtil.killCaches(...) ");
         }

      }
      threadTestName.set(currentTestName);
   }

   private String extractTestName()
   {
      StackTraceElement[] stack = Thread.currentThread().getStackTrace();
      if (stack.length == 0) return null;
      for (int i = stack.length - 1; i > 0; i--)
      {
         StackTraceElement e = stack[i];
         String className = e.getClassName();
         if (className.indexOf("org.jboss.cache") != -1) return className; //+ "." + e.getMethodName();
      }
      return null;
   }
}
TOP

Related Classes of org.jboss.cache.UnitTestCacheFactory

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.