[exo-jcr-commits] exo-jcr SVN: r2180 - in jcr/trunk/exo.jcr.component.core/src: test/java/org/exoplatform/services/jcr/impl/dataflow/persistent and 1 other directory.

do-not-reply at jboss.org do-not-reply at jboss.org
Mon Mar 29 13:52:56 EDT 2010


Author: nfilotto
Date: 2010-03-29 13:52:56 -0400 (Mon, 29 Mar 2010)
New Revision: 2180

Added:
   jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
Modified:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
Log:
EXOJCR-613: We ensure that we never access more than once to the database when several concurrent threads try to access to the same data at the same time. We also ensure that we create the object DataRequest only when it is required which means only when we have to access to the database.

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java	2010-03-29 13:25:16 UTC (rev 2179)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java	2010-03-29 17:52:56 UTC (rev 2180)
@@ -31,9 +31,9 @@
 import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
 import org.exoplatform.services.transaction.TransactionService;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CountDownLatch;
 
 import javax.jcr.RepositoryException;
@@ -59,7 +59,7 @@
    /**
     * Requests cache.
     */
-   protected final Map<Integer, DataRequest> requestCache;
+   protected final ConcurrentMap<Integer, DataRequest> requestCache;
 
    private TransactionManager transactionManager;
 
@@ -91,6 +91,11 @@
       static private final int GET_ITEM_NAME = 4;
 
       /**
+       * GET_LIST_PROPERTIES type.
+       */
+      static private final int GET_LIST_PROPERTIES = 4;
+      
+      /**
        * Request type.
        */
       protected final int type;
@@ -173,43 +178,29 @@
          this.type = GET_ITEM_ID;
 
          // hashcode
-         this.hcode = 31 * (31 + this.type) + this.id.hashCode();
+         this.hcode = 31 * (31 + this.type) + (this.id == null ? 0 : this.id.hashCode());
       }
 
       /**
-       * Find the same, and if found wait till the one will be finished.
-       * 
-       * WARNING. This method effective with cache use only!!! Without cache the database will control
-       * requests performance/chaching process.
-       * 
-       * @return this data request
+       * Start the request, each same will wait till this will be finished
        */
-      DataRequest waitSame()
+      void start()
       {
-         DataRequest prev = requestCache.get(this.hashCode());
-         if (prev != null)
+         DataRequest request = requestCache.putIfAbsent(this.hashCode(), this);
+         if (request != null)
          {
-            prev.await();
+            request.await();
          }
-         return this;
       }
 
       /**
-       * Start the request, each same will wait till this will be finished
-       */
-      void start()
-      {
-         requestCache.put(this.hashCode(), this);
-      }
-
-      /**
        * Done the request. Must be called after the data request will be finished. This call allow
        * another same requests to be performed.
        */
       void done()
       {
          this.ready.countDown();
-         requestCache.remove(this.hashCode());
+         requestCache.remove(this.hashCode(), this);
       }
 
       /**
@@ -298,7 +289,7 @@
       super(dataContainer, systemDataContainerHolder);
       this.cache = cache;
 
-      this.requestCache = new HashMap<Integer, DataRequest>();
+      this.requestCache = new ConcurrentHashMap<Integer, DataRequest>();
       addItemPersistenceListener(cache);
 
       transactionManager = transactionService.getTransactionManager();
@@ -320,7 +311,7 @@
       super(dataContainer, systemDataContainerHolder);
       this.cache = cache;
 
-      this.requestCache = new HashMap<Integer, DataRequest>();
+      this.requestCache = new ConcurrentHashMap<Integer, DataRequest>();
       addItemPersistenceListener(cache);
 
       if (cache instanceof JBossCacheWorkspaceStorageCache)
@@ -394,7 +385,23 @@
       // 2. Try from container
       if (data == null)
       {
-         data = getPersistedItemData(parentData, name);
+         final DataRequest request = new DataRequest(parentData.getIdentifier(), name);
+         
+         try
+         {
+            request.start();
+            // Try first to get the value from the cache since a
+            // request could have been launched just before
+            data = getCachedItemData(parentData, name);
+            if (data == null)
+            {
+               data = getPersistedItemData(parentData, name);               
+            }
+         }
+         finally
+         {
+            request.done();
+         }
       }
       else if (!data.isNode())
       {
@@ -415,7 +422,23 @@
       // 3. Try from container
       if (data == null)
       {
-         return getPersistedItemData(identifier);
+         final DataRequest request = new DataRequest(identifier);
+         
+         try
+         {
+            request.start();
+            // Try first to get the value from the cache since a
+            // request could have been launched just before
+            data = getCachedItemData(identifier);
+            if (data == null)
+            {
+               data = getPersistedItemData(identifier);               
+            }
+         }
+         finally
+         {
+            request.done();
+         }
       }
       else if (!data.isNode())
       {
@@ -508,22 +531,30 @@
       throws RepositoryException
    {
 
-      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_NODES);
-
       List<NodeData> childNodes = null;
       if (!forcePersistentRead && cache.isEnabled())
       {
-         request.waitSame();
          childNodes = cache.getChildNodes(nodeData);
          if (childNodes != null)
          {
             return childNodes;
          }
       }
+      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_NODES);
 
       try
       {
          request.start();
+         if (!forcePersistentRead && cache.isEnabled())
+         {
+            // Try first to get the value from the cache since a
+            // request could have been launched just before
+            childNodes = cache.getChildNodes(nodeData);
+            if (childNodes != null)
+            {
+               return childNodes;
+            }
+         }
          childNodes = super.getChildNodesData(nodeData);
          if (cache.isEnabled())
          {
@@ -535,9 +566,7 @@
 
             if (parentData != null)
             {
-               {
-                  cache.addChildNodes(parentData, childNodes);
-               }
+               cache.addChildNodes(parentData, childNodes);
             }
          }
          return childNodes;
@@ -563,22 +592,30 @@
       throws RepositoryException
    {
 
-      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_PROPERTIES);
-
       List<PropertyData> childProperties = null;
       if (!forcePersistentRead && cache.isEnabled())
       {
-         request.waitSame();
          childProperties = cache.getChildProperties(nodeData);
          if (childProperties != null)
          {
             return childProperties;
          }
       }
+      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_PROPERTIES);
 
       try
       {
          request.start();
+         if (!forcePersistentRead && cache.isEnabled())
+         {
+            // Try first to get the value from the cache since a
+            // request could have been launched just before
+            childProperties = cache.getChildProperties(nodeData);
+            if (childProperties != null)
+            {
+               return childProperties;
+            }
+         }
 
          childProperties = super.getChildPropertiesData(nodeData);
          // TODO childProperties.size() > 0 for SDB
@@ -592,9 +629,7 @@
 
             if (parentData != null)
             {
-               {
-                  cache.addChildProperties(parentData, childProperties);
-               }
+               cache.addChildProperties(parentData, childProperties);
             }
          }
          return childProperties;
@@ -621,9 +656,7 @@
       ItemData data = super.getItemData(parentData, name);
       if (data != null && cache.isEnabled())
       {
-         {
-            cache.put(data);
-         }
+         cache.put(data);
       }
       return data;
    }
@@ -640,9 +673,7 @@
       ItemData data = super.getItemData(identifier);
       if (data != null && cache.isEnabled())
       {
-         {
-            cache.put(data);
-         }
+         cache.put(data);
       }
       return data;
    }
@@ -662,12 +693,9 @@
       throws RepositoryException
    {
 
-      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_PROPERTIES);
-
       List<PropertyData> propertiesList;
       if (!forcePersistentRead && cache.isEnabled())
       {
-         request.waitSame(); // wait if getChildProp... working somewhere
          propertiesList = cache.listChildProperties(nodeData);
          if (propertiesList != null)
          {
@@ -675,24 +703,41 @@
          }
       }
 
-      propertiesList = super.listChildPropertiesData(nodeData);
-      // TODO propertiesList.size() > 0 for SDB
-      if (propertiesList.size() > 0 && cache.isEnabled())
+      final DataRequest request = new DataRequest(nodeData.getIdentifier(), DataRequest.GET_LIST_PROPERTIES);
+      try
       {
-         NodeData parentData = (NodeData)cache.get(nodeData.getIdentifier());
-         if (parentData == null)
+         request.start();
+         if (!forcePersistentRead && cache.isEnabled())
          {
-            parentData = (NodeData)super.getItemData(nodeData.getIdentifier());
+            // Try first to get the value from the cache since a
+            // request could have been launched just before
+            propertiesList = cache.listChildProperties(nodeData);
+            if (propertiesList != null)
+            {
+               return propertiesList;
+            }
          }
-
-         if (parentData != null)
+         propertiesList = super.listChildPropertiesData(nodeData);
+         // TODO propertiesList.size() > 0 for SDB
+         if (propertiesList.size() > 0 && cache.isEnabled())
          {
+            NodeData parentData = (NodeData)cache.get(nodeData.getIdentifier());
+            if (parentData == null)
             {
+               parentData = (NodeData)super.getItemData(nodeData.getIdentifier());
+            }
+
+            if (parentData != null)
+            {
                cache.addChildPropertiesList(parentData, propertiesList);
             }
          }
+         return propertiesList;
       }
-      return propertiesList;
+      finally
+      {
+         request.done();
+      }      
    }
 
    protected boolean isTxAware()

Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java	2010-03-29 17:52:56 UTC (rev 2180)
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
+import org.exoplatform.services.jcr.impl.storage.WorkspaceDataContainerBase;
+import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
+import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 29 mars 2010  
+ */
+public class TestCacheableWorkspaceDataManager extends TestCase
+{
+
+   private static final int READER = 100;
+   private static final int TIMES = 20;
+
+   private CacheableWorkspaceDataManager cwdm;
+
+   private WorkspaceDataContainer wdc;
+
+   private MyWorkspaceStorageConnection con;
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      this.con = new MyWorkspaceStorageConnection();
+      this.wdc = new MyWorkspaceDataContainer(con);
+      this.cwdm =
+         new CacheableWorkspaceDataManager(wdc, new MyWorkspaceStorageCache(), new SystemDataContainerHolder(wdc));
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      this.con = null;
+      this.wdc = null;
+      this.cwdm = null;
+      super.tearDown();
+   }
+
+   private void multiThreadingTest(final MyTask task) throws Exception
+   {
+      final CountDownLatch startSignal = new CountDownLatch(1);
+      final CountDownLatch doneSignal = new CountDownLatch(READER);
+      final List<Exception> errors = Collections.synchronizedList(new ArrayList<Exception>());
+      for (int i = 0; i < READER; i++)
+      {
+         Thread thread = new Thread()
+         {
+            public void run()
+            {
+               try
+               {
+                  startSignal.await();
+                  for (int i = 0; i < TIMES; i++)
+                  {
+                     task.execute();                     
+                  }
+               }
+               catch (Exception e)
+               {
+                  errors.add(e);
+               }
+               finally
+               {
+                  doneSignal.countDown();
+               }
+            }
+         };
+         thread.start();
+      }
+      long time = System.currentTimeMillis();
+      startSignal.countDown();
+      doneSignal.await();
+      System.out.println("Total Time = " + (System.currentTimeMillis() - time));
+      if (!errors.isEmpty())
+      {
+         for (Exception e : errors)
+         {
+            e.printStackTrace();
+         }
+         throw errors.get(0);
+      }      
+   }
+   
+   public void testGetItemById() throws Exception
+   {
+      assertEquals(0, con.getItemDataByIdCalls.get());
+      MyTask task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            ItemData item = cwdm.getItemData("getItemData");
+            assertNotNull(item);
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1, con.getItemDataByIdCalls.get());
+   }
+   
+   public void testGetItemDataByNodeDataNQPathEntry() throws Exception
+   {
+      final NodeData nodeData = new PersistedNodeData("getItemData", null, null, 0, 1, null, null, null); 
+      assertEquals(0, con.getItemDataByNodeDataNQPathEntryCalls.get());
+      MyTask task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            ItemData item = cwdm.getItemData(nodeData, new QPathEntry("http://www.foo.com", "foo", 0));
+            assertNotNull(item);
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1, con.getItemDataByNodeDataNQPathEntryCalls.get());
+   }
+   
+   public void testGetChildPropertiesData() throws Exception
+   {
+      final NodeData nodeData = new PersistedNodeData("getChildPropertiesData", null, null, 0, 1, null, null, null); 
+      assertEquals(0, con.getChildPropertiesDataCalls.get());
+      MyTask task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<PropertyData> properties = cwdm.getChildPropertiesData(nodeData);
+            assertNotNull(properties);
+            assertFalse(properties.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1, con.getChildPropertiesDataCalls.get());
+      task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<PropertyData> properties = cwdm.getChildPropertiesData(nodeData, true);
+            assertNotNull(properties);
+            assertFalse(properties.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1 + READER * TIMES, con.getChildPropertiesDataCalls.get());
+   }
+   
+   public void testListChildPropertiesData() throws Exception
+   {
+      final NodeData nodeData = new PersistedNodeData("listChildPropertiesData", null, null, 0, 1, null, null, null); 
+      assertEquals(0, con.listChildPropertiesDataCalls.get());
+      MyTask task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<PropertyData> properties = cwdm.listChildPropertiesData(nodeData);
+            assertNotNull(properties);
+            assertFalse(properties.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1, con.listChildPropertiesDataCalls.get());
+      task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<PropertyData> properties = cwdm.listChildPropertiesData(nodeData, true);
+            assertNotNull(properties);
+            assertFalse(properties.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1 + READER * TIMES, con.listChildPropertiesDataCalls.get());
+   }
+   
+   public void testGetChildNodes() throws Exception
+   {
+      final NodeData nodeData = new PersistedNodeData("getChildNodes", null, null, 0, 1, null, null, null); 
+      assertEquals(0, con.getChildNodesDataCalls.get());
+      MyTask task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<NodeData> nodes = cwdm.getChildNodesData(nodeData);
+            assertNotNull(nodes);
+            assertFalse(nodes.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1, con.getChildNodesDataCalls.get());
+      task = new MyTask()
+      {
+         public void execute() throws Exception
+         {
+            List<NodeData> nodes = cwdm.getChildNodesData(nodeData, true);
+            assertNotNull(nodes);
+            assertFalse(nodes.isEmpty());
+         }         
+      };
+      multiThreadingTest(task);
+      assertEquals(1 + READER * TIMES, con.getChildNodesDataCalls.get());
+   }
+
+   private static interface MyTask
+   {
+      void execute() throws Exception;
+   }
+   
+   private static class MyWorkspaceStorageCache implements WorkspaceStorageCache
+   {
+
+      private volatile List<NodeData> childNodes;
+
+      public void addChildNodes(NodeData parent, List<NodeData> childNodes)
+      {
+         this.childNodes = childNodes;
+      }
+
+      private volatile List<PropertyData> childProperties;
+
+      public void addChildProperties(NodeData parent, List<PropertyData> childProperties)
+      {
+         this.childProperties = childProperties;
+      }
+
+      private volatile List<PropertyData> childPropertiesList;
+
+      public void addChildPropertiesList(NodeData parent, List<PropertyData> childProperties)
+      {
+         this.childPropertiesList = childProperties;
+      }
+
+      public void beginTransaction()
+      {
+      }
+
+      public void commitTransaction()
+      {
+      }
+
+      private volatile ItemData itemData;
+
+      public ItemData get(String parentIdentifier, QPathEntry name)
+      {
+         return itemData;
+      }
+
+      public ItemData get(String identifier)
+      {
+         return itemData;
+      }
+
+      public List<NodeData> getChildNodes(NodeData parent)
+      {
+         return childNodes;
+      }
+
+      public List<PropertyData> getChildProperties(NodeData parent)
+      {
+         return childProperties;
+      }
+
+      public long getSize()
+      {
+         return 0;
+      }
+
+      public boolean isEnabled()
+      {
+         return true;
+      }
+
+      public List<PropertyData> listChildProperties(NodeData parentData)
+      {
+         return childPropertiesList;
+      }
+
+      public void put(ItemData item)
+      {
+         this.itemData = item;
+      }
+
+      public void remove(ItemData item)
+      {
+         this.itemData = null;
+      }
+
+      public void rollbackTransaction()
+      {
+      }
+
+      public boolean isTXAware()
+      {
+         return true;
+      }
+
+      public void onSaveItems(ItemStateChangesLog itemStates)
+      {
+      }
+
+   }
+
+   private static class MyWorkspaceStorageConnection implements WorkspaceStorageConnection
+   {
+
+      public void add(NodeData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public void add(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public void close() throws IllegalStateException, RepositoryException
+      {
+      }
+
+      public void commit() throws IllegalStateException, RepositoryException
+      {
+      }
+
+      public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public void delete(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public AtomicInteger getChildNodesCountCalls = new AtomicInteger();
+
+      public int getChildNodesCount(NodeData parent) throws RepositoryException
+      {
+         getChildNodesCountCalls.incrementAndGet();
+         return 1;
+      }
+
+      public AtomicInteger getChildNodesDataCalls = new AtomicInteger();
+
+      public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException
+      {
+         getChildNodesDataCalls.incrementAndGet();
+         return Arrays.asList((NodeData)new PersistedNodeData("getChildNodesData", null, null, 0, 1, null, null, null));
+      }
+
+      public AtomicInteger getChildPropertiesDataCalls = new AtomicInteger();
+
+      public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException,
+         IllegalStateException
+      {
+         getChildPropertiesDataCalls.incrementAndGet();
+         return Arrays
+            .asList((PropertyData)new PersistedPropertyData("getChildPropertiesData", null, null, 0,
+               PropertyType.STRING, false, Arrays
+                  .asList((ValueData)new ByteArrayPersistedValueData(1, "foo".getBytes()))));
+      }
+
+      public AtomicInteger getItemDataByNodeDataNQPathEntryCalls = new AtomicInteger();
+
+      public ItemData getItemData(NodeData parentData, QPathEntry name) throws RepositoryException,
+         IllegalStateException
+      {
+         getItemDataByNodeDataNQPathEntryCalls.incrementAndGet();
+         return new PersistedNodeData("getItemData", null, null, 0, 1, null, null, null);
+      }
+
+      public AtomicInteger getItemDataByIdCalls = new AtomicInteger();
+
+      public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException
+      {
+         getItemDataByIdCalls.incrementAndGet();
+         return new PersistedNodeData("getItemData", null, null, 0, 1, null, null, null);
+      }
+
+      public AtomicInteger getReferencesDataCalls = new AtomicInteger();
+
+      public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
+         IllegalStateException, UnsupportedOperationException
+      {
+         getReferencesDataCalls.incrementAndGet();
+         return Arrays
+            .asList((PropertyData)new PersistedPropertyData("getReferencesData", null, null, 0, PropertyType.STRING,
+               false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(1, "foo".getBytes()))));
+      }
+
+      public boolean isOpened()
+      {
+         return true;
+      }
+
+      public AtomicInteger listChildPropertiesDataCalls = new AtomicInteger();
+
+      public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException,
+         IllegalStateException
+      {
+         listChildPropertiesDataCalls.incrementAndGet();
+         return Arrays.asList((PropertyData)new PersistedPropertyData("listChildPropertiesData", null, null, 0, PropertyType.STRING,
+            false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(1, "foo".getBytes()))));
+      }
+
+      public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public void rollback() throws IllegalStateException, RepositoryException
+      {
+      }
+
+      public void update(NodeData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+      public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+         InvalidItemStateException, IllegalStateException
+      {
+      }
+
+   };
+
+   private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
+   {
+
+      private WorkspaceStorageConnection con;
+
+      public MyWorkspaceDataContainer(WorkspaceStorageConnection con)
+      {
+         this.con = con;
+      }
+
+      public boolean isCheckSNSNewConnection()
+      {
+         return false;
+      }
+
+      public boolean isSame(WorkspaceDataContainer another)
+      {
+         return false;
+      }
+
+      public WorkspaceStorageConnection openConnection() throws RepositoryException
+      {
+         return con;
+      }
+
+      public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
+      {
+         return con;
+      }
+
+      public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException
+      {
+         return con;
+      }
+
+      public String getInfo()
+      {
+         return "MyWorkspaceDataContainer";
+      }
+
+      public String getName()
+      {
+         return "MyWorkspaceDataContainer";
+      }
+
+      public String getStorageVersion()
+      {
+         return "0";
+      }
+
+   };
+
+}



More information about the exo-jcr-commits mailing list