[exo-jcr-commits] exo-jcr SVN: r3910 - kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl and 2 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Tue Feb 1 12:50:06 EST 2011


Author: nfilotto
Date: 2011-02-01 12:50:06 -0500 (Tue, 01 Feb 2011)
New Revision: 3910

Modified:
   jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
   kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
   kernel/trunk/exo.kernel.component.cache/src/test/java/org/exoplatform/services/cache/test/TestCacheService.java
   kernel/trunk/exo.kernel.component.cache/src/test/resources/conf/portal/test-configuration.xml
Log:
EXOJCR-1179: Bug fixed
EXOJCR-1180: Improvement implemented to avoid the bug

Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml	2011-02-01 14:14:32 UTC (rev 3909)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml	2011-02-01 17:50:06 UTC (rev 3910)
@@ -176,7 +176,14 @@
     <type>org.exoplatform.tutorial.MyExoCacheFactoryImpl</type>
     ...
   </component>   
-&lt;/configuration&gt;</programlisting></para>
+&lt;/configuration&gt;</programlisting><note>
+        <para>Since kernel 2.3.0-CR1, if the configuration is not a sub class
+        of <envar>ExoCacheConfig</envar> and the implementation given in the
+        configuration is the full qualified name of an existing implementation
+        of eXo Cache, we will assume that the user expects to have an instance
+        of this eXo Cache type so we won't use the configured cache
+        factory.</para>
+      </note></para>
   </section>
 
   <section>

Modified: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java	2011-02-01 14:14:32 UTC (rev 3909)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java	2011-02-01 17:50:06 UTC (rev 3910)
@@ -28,12 +28,19 @@
 import org.exoplatform.services.cache.ExoCacheFactory;
 import org.exoplatform.services.cache.ExoCacheInitException;
 import org.exoplatform.services.cache.SimpleExoCache;
+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
@@ -42,11 +49,18 @@
 @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, ExoCache<? extends Serializable, ?>> cacheMap_ =
-      new ConcurrentHashMap<String, ExoCache<? extends Serializable, ?>>();
-
+   private final ConcurrentHashMap<String, FutureExoCacheCreationTask> cacheMap_ =
+      new ConcurrentHashMap<String, FutureExoCacheCreationTask>();
+   
    private final ExoCacheConfig defaultConfig_;
 
    private final LoggingCacheListener loggingListener_;
@@ -72,7 +86,7 @@
       }
       defaultConfig_ = configs_.get("default");
       loggingListener_ = new LoggingCacheListener();
-      factory_ = factory == null ? new SimpleExoCacheFactory() : factory;
+      factory_ = factory == null ? DEFAULT_FACTORY : factory;
    }
 
    public void addExoCacheConfig(ComponentPlugin plugin)
@@ -89,7 +103,8 @@
       }
    }
 
-   public <K extends Serializable, V> ExoCache<K, V> getCacheInstance(String region)
+   @SuppressWarnings("unchecked")
+   public <K extends Serializable, V> ExoCache<K, V> getCacheInstance(final String region)
    {
       if (region == null)
       {
@@ -99,27 +114,47 @@
       {
          throw new IllegalArgumentException("region cannot be empty");
       }
-      ExoCache<? extends Serializable, ?> cache = cacheMap_.get(region);
-      if (cache == null)
+      FutureExoCacheCreationTask creationTask = cacheMap_.get(region);
+      if (creationTask == null)
       {
-         try
+         Callable<ExoCache<? extends Serializable,?>> task = new Callable<ExoCache<? extends Serializable,?>>()
          {
-            cache = createCacheInstance(region);
-            ExoCache<? extends Serializable, ?> existing = cacheMap_.putIfAbsent(region, cache);
-            if (existing != null)
+            public ExoCache<? extends Serializable, ?> call() throws Exception
             {
-               cache = existing;
+               return createCacheInstance(region);
             }
+         };
+         creationTask = new FutureExoCacheCreationTask(task);
+         FutureExoCacheCreationTask existingTask = cacheMap_.putIfAbsent(region, creationTask);
+         if (existingTask != null)
+         {
+            creationTask = existingTask;
          }
-         catch (Exception e)
+         else
          {
-            e.printStackTrace();
+            creationTask.run();
          }
       }
-      return (ExoCache<K, V>)cache;
+      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;
    }
 
-   synchronized private ExoCache<? extends Serializable, ?> createCacheInstance(String region) throws Exception
+   private ExoCache<? extends Serializable, ?> createCacheInstance(String region) throws Exception
    {
       ExoCacheConfig config = configs_.get(region);
       if (config == null)
@@ -129,8 +164,36 @@
       final ExoCacheConfig safeConfig = config.clone();
       // Set the region as name 
       safeConfig.setName(region);
-      final ExoCache simple = factory_.createCache(safeConfig);
-
+      
+      ExoCache simple = null;
+      if (factory_ != DEFAULT_FACTORY && safeConfig.getClass().isAssignableFrom(ExoCacheConfig.class)
+         && 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
+         {
+            final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            // We check if the given implementation is a known class
+            Class implClass = cl.loadClass(safeConfig.getImplementation());            
+            // 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)
+         {
+            // The implementation could not be found
+         }
+      }
+      if (simple == null)
+      {
+         // We use the configured cache factory
+         simple = factory_.createCache(safeConfig);
+      }
+      
       if (managed != null)
       {
          managed.registerCache(simple);
@@ -140,7 +203,24 @@
 
    public Collection<ExoCache<? extends Serializable, ?>> getAllCacheInstances()
    {
-      return cacheMap_.values();
+      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 (Exception e)
+         {
+            // ignore me
+         }
+         if (cache != null)
+         {
+            caches.add(cache);            
+         }
+      }
+      return caches;
    }
 
    /**
@@ -203,4 +283,31 @@
          }
       }
    }
+   
+   /**
+    * 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();
+      }
+   }
 }

Modified: kernel/trunk/exo.kernel.component.cache/src/test/java/org/exoplatform/services/cache/test/TestCacheService.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/test/java/org/exoplatform/services/cache/test/TestCacheService.java	2011-02-01 14:14:32 UTC (rev 3909)
+++ kernel/trunk/exo.kernel.component.cache/src/test/java/org/exoplatform/services/cache/test/TestCacheService.java	2011-02-01 17:50:06 UTC (rev 3910)
@@ -19,17 +19,31 @@
 package org.exoplatform.services.cache.test;
 
 import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ObjectParameter;
+import org.exoplatform.services.cache.CacheListener;
 import org.exoplatform.services.cache.CacheService;
+import org.exoplatform.services.cache.CachedObjectSelector;
 import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ExoCacheConfig;
+import org.exoplatform.services.cache.ExoCacheFactory;
+import org.exoplatform.services.cache.ExoCacheInitException;
 import org.exoplatform.services.cache.FIFOExoCache;
 import org.exoplatform.services.cache.SimpleExoCache;
+import org.exoplatform.services.cache.concurrent.ConcurrentFIFOExoCache;
+import org.exoplatform.services.cache.impl.CacheServiceImpl;
 import org.exoplatform.test.BasicTestCase;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanInfo;
@@ -194,6 +208,179 @@
      }
    */
 
+   public void testConcurrentCreation() throws Exception
+   {
+      int threads = 20;
+      final CountDownLatch startSignal = new CountDownLatch(1);
+      final CountDownLatch doneSignal = new CountDownLatch(threads);
+      final List<Exception> errors = Collections.synchronizedList(new ArrayList<Exception>());
+      for (int i = 0; i < threads; i++)
+      {
+         Thread thread = new Thread()
+         {
+            public void run()
+            {
+               try
+               {
+                  startSignal.await();
+                  assertNotNull(service_.getCacheInstance("TestConcurrentCreation"));
+               }
+               catch (Exception e)
+               {
+                  errors.add(e);
+               }
+               finally
+               {
+                  doneSignal.countDown();
+               }
+            }
+         };
+         thread.start();
+      }
+      startSignal.countDown();
+      doneSignal.await();
+      if (!errors.isEmpty())
+      {
+         for (Exception e : errors)
+         {
+            e.printStackTrace();
+         }
+         throw errors.get(0);
+      }
+      assertEquals(1, MyExoCache.count.get());
+   }
+   
+   public void testGetAllCacheInstances() throws Exception
+   {
+      assertNotNull(service_.getAllCacheInstances());
+      assertEquals(8, service_.getAllCacheInstances().size());
+   }
+   
+   public void testPerf() throws Exception
+   {
+      // Pre-create it 
+      service_.getCacheInstance("FooCache");
+      int threads = 100;
+      final CountDownLatch startSignal = new CountDownLatch(1);
+      final CountDownLatch doneSignal = new CountDownLatch(threads);
+      final List<Exception> errors = Collections.synchronizedList(new ArrayList<Exception>());
+      for (int i = 0; i < threads; i++)
+      {
+         Thread thread = new Thread()
+         {
+            public void run()
+            {
+               try
+               {
+                  startSignal.await();
+                  for (int i = 0; i < 1000000; i++)
+                  {
+                     assertNotNull(service_.getCacheInstance("FooCache"));                     
+                  }
+               }
+               catch (Exception e)
+               {
+                  errors.add(e);
+               }
+               finally
+               {
+                  doneSignal.countDown();
+               }
+            }
+         };
+         thread.start();
+      }
+      long start = System.currentTimeMillis();
+      startSignal.countDown();
+      doneSignal.await();
+      System.out.println("Total Time = " + (System.currentTimeMillis() - start));
+      if (!errors.isEmpty())
+      {
+         for (Exception e : errors)
+         {
+            e.printStackTrace();
+         }
+         throw errors.get(0);
+      }      
+   }
+   
+   public void testCacheFactory() throws Exception
+   {
+      InitParams params = new InitParams();
+      ObjectParameter param = new ObjectParameter();
+      param.setName("NoImpl");
+      ExoCacheConfig config = new ExoCacheConfig();
+      config.setName(param.getName());
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("KnownImpl");
+      config = new ExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("org.exoplatform.services.cache.concurrent.ConcurrentFIFOExoCache");
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("UnKnownImpl");
+      config = new ExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("fakeImpl");
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("UnKnownImplButCorrectFQN");
+      config = new ExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("java.lang.String");
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("NoImpl-MyExoCacheConfig");
+      config = new MyExoCacheConfig();
+      config.setName(param.getName());
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("KnownImpl-MyExoCacheConfig");
+      config = new MyExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("org.exoplatform.services.cache.FIFOExoCache");
+      param.setObject(config);
+      params.addParameter(param);
+      
+      param = new ObjectParameter();
+      param.setName("UnKnownImpl-MyExoCacheConfig");
+      config = new MyExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("fakeImpl");
+      param.setObject(config);
+      params.addParameter(param);
+      
+      
+      param = new ObjectParameter();
+      param.setName("UnKnownImplButCorrectFQN-MyExoCacheConfig");
+      config = new MyExoCacheConfig();
+      config.setName(param.getName());
+      config.setImplementation("java.lang.String");
+      param.setObject(config);
+      params.addParameter(param);
+
+      CacheService cs = new CacheServiceImpl(params, new MyExoCacheFactory());
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("NoImpl").getClass(), cs.getCacheInstance("NoImpl") instanceof MyExoCache);
+      assertTrue("Expected type ConcurrentFIFOExoCache found " + cs.getCacheInstance("KnownImpl").getClass(), cs.getCacheInstance("KnownImpl") instanceof ConcurrentFIFOExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("UnKnownImpl").getClass(), cs.getCacheInstance("UnKnownImpl") instanceof MyExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("UnKnownImplButCorrectFQN").getClass(), cs.getCacheInstance("UnKnownImplButCorrectFQN") instanceof MyExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("NoImpl-MyExoCacheConfig").getClass(), cs.getCacheInstance("NoImpl-MyExoCacheConfig") instanceof MyExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("KnownImpl-MyExoCacheConfig").getClass(), cs.getCacheInstance("KnownImpl-MyExoCacheConfig") instanceof MyExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("UnKnownImpl-MyExoCacheConfig").getClass(), cs.getCacheInstance("UnKnownImpl-MyExoCacheConfig") instanceof MyExoCache);
+      assertTrue("Expected type MyExoCache found " + cs.getCacheInstance("UnKnownImplButCorrectFQN-MyExoCacheConfig").getClass(), cs.getCacheInstance("UnKnownImplButCorrectFQN-MyExoCacheConfig") instanceof MyExoCache);
+   }
+   
    private static class ExoCacheComparator implements Comparator
    {
 
@@ -214,4 +401,202 @@
    {
       return "Test Cache Service";
    }
+   
+   public static class MyExoCache<V> implements ExoCache<Serializable, V>
+   {
+
+      private static AtomicInteger count = new AtomicInteger();
+      
+      public MyExoCache()
+      {
+         count.incrementAndGet();
+      }
+      
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getName()
+       */
+      public String getName()
+      {
+         return "TestConcurrentCreation";
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#setName(java.lang.String)
+       */
+      public void setName(String name)
+      {
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getLabel()
+       */
+      public String getLabel()
+      {
+         return "TestConcurrentCreation";
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#setLabel(java.lang.String)
+       */
+      public void setLabel(String s)
+      {
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#get(java.io.Serializable)
+       */
+      public V get(Serializable key)
+      {
+         return null;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#remove(java.io.Serializable)
+       */
+      public V remove(Serializable key) throws NullPointerException
+      {
+         return null;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#put(java.io.Serializable, java.lang.Object)
+       */
+      public void put(Serializable key, V value) throws NullPointerException
+      {
+         
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#putMap(java.util.Map)
+       */
+      public void putMap(Map<? extends Serializable, ? extends V> objs) throws NullPointerException,
+         IllegalArgumentException
+      {
+         
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#clearCache()
+       */
+      public void clearCache()
+      {
+         
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#select(org.exoplatform.services.cache.CachedObjectSelector)
+       */
+      public void select(CachedObjectSelector<? super Serializable, ? super V> selector) throws Exception
+      {
+         
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getCacheSize()
+       */
+      public int getCacheSize()
+      {
+         return 0;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getMaxSize()
+       */
+      public int getMaxSize()
+      {
+         return 0;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#setMaxSize(int)
+       */
+      public void setMaxSize(int max)
+      {
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getLiveTime()
+       */
+      public long getLiveTime()
+      {
+         return 0;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#setLiveTime(long)
+       */
+      public void setLiveTime(long period)
+      {
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getCacheHit()
+       */
+      public int getCacheHit()
+      {
+         return 0;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getCacheMiss()
+       */
+      public int getCacheMiss()
+      {
+         return 0;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#getCachedObjects()
+       */
+      public List<? extends V> getCachedObjects() throws Exception
+      {
+         return null;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#removeCachedObjects()
+       */
+      public List<? extends V> removeCachedObjects()
+      {
+         return null;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#addCacheListener(org.exoplatform.services.cache.CacheListener)
+       */
+      public void addCacheListener(CacheListener<? super Serializable, ? super V> listener) throws NullPointerException
+      {
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#isLogEnabled()
+       */
+      public boolean isLogEnabled()
+      {
+         return false;
+      }
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCache#setLogEnabled(boolean)
+       */
+      public void setLogEnabled(boolean b)
+      {
+      }
+      
+   }
+   
+   public static class MyExoCacheFactory implements ExoCacheFactory
+   {
+
+      /**
+       * @see org.exoplatform.services.cache.ExoCacheFactory#createCache(org.exoplatform.services.cache.ExoCacheConfig)
+       */
+      public ExoCache createCache(ExoCacheConfig config) throws ExoCacheInitException
+      {
+         return new MyExoCache();
+      }
+      
+   }
+   
+   public static class MyExoCacheConfig extends ExoCacheConfig {}
 }

Modified: kernel/trunk/exo.kernel.component.cache/src/test/resources/conf/portal/test-configuration.xml
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/test/resources/conf/portal/test-configuration.xml	2011-02-01 14:14:32 UTC (rev 3909)
+++ kernel/trunk/exo.kernel.component.cache/src/test/resources/conf/portal/test-configuration.xml	2011-02-01 17:50:06 UTC (rev 3910)
@@ -223,6 +223,31 @@
                </object>
             </object-param>
 
+            <object-param>
+               <name>TestConcurrentCreationPlugin</name>
+               <description>cache used to test the concurrent creation</description>
+               <object type="org.exoplatform.services.cache.ExoCacheConfig">
+                  <field name="name">
+                     <string>TestConcurrentCreation</string>
+                  </field>
+                  <field name="implementation">
+                     <string>org.exoplatform.services.cache.test.TestCacheService$MyExoCache</string>
+                  </field>
+               </object>
+            </object-param>
+
+            <object-param>
+               <name>TestErrorCreationPlugin</name>
+               <description>cache used to test the concurrent creation</description>
+               <object type="org.exoplatform.services.cache.ExoCacheConfig">
+                  <field name="name">
+                     <string>TestErrorCreation</string>
+                  </field>
+                  <field name="implementation">
+                     <string>org.exoplatform.services.cache.test.TestCacheService$MyExoCacheFake</string>
+                  </field>
+               </object>
+            </object-param>
          </init-params>
       </component-plugin>
    </external-component-plugins>



More information about the exo-jcr-commits mailing list