[exo-jcr-commits] exo-jcr SVN: r782 - in jcr/branches/1.12.0-JBC/component/core/src: test/java/org/exoplatform/services/jcr/impl/storage/jbosscache and 1 other directory.

do-not-reply at jboss.org do-not-reply at jboss.org
Thu Nov 19 11:19:28 EST 2009


Author: sergiykarpenko
Date: 2009-11-19 11:19:28 -0500 (Thu, 19 Nov 2009)
New Revision: 782

Modified:
   jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorage.java
   jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnection.java
   jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheWorkspaceDataContainer.java
   jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractJBossCacheStorageConnectionTest.java
   jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnectionTest.java
Log:
EXOJCR-246: reference support added

Modified: jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorage.java
===================================================================
--- jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorage.java	2009-11-19 15:56:16 UTC (rev 781)
+++ jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorage.java	2009-11-19 16:19:28 UTC (rev 782)
@@ -44,6 +44,8 @@
 
    public static final String LOCKS = "$LOCKS".intern();
 
+   public static final String REFS = "$REFS".intern();
+
    public static final String ITEM_DATA = "$data".intern();
 
    public static final String ITEM_ID = "$id".intern();
@@ -62,14 +64,18 @@
 
    protected final Node<Serializable, Object> locksRoot;
 
+   protected final Node<Serializable, Object> refsRoot;
+
    protected JBossCacheStorage(Node<Serializable, Object> nodesRoot, Node<Serializable, Object> propsRoot,
-      Node<Serializable, Object> locksRoot)
+      Node<Serializable, Object> locksRoot, Node<Serializable, Object> refsRoot)
    {
       this.nodesRoot = nodesRoot;
 
       this.propsRoot = propsRoot;
 
       this.locksRoot = locksRoot;
+
+      this.refsRoot = refsRoot;
    }
 
    /**

Modified: jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnection.java
===================================================================
--- jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnection.java	2009-11-19 15:56:16 UTC (rev 781)
+++ jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnection.java	2009-11-19 16:19:28 UTC (rev 782)
@@ -18,13 +18,17 @@
  */
 package org.exoplatform.services.jcr.impl.storage.jbosscache;
 
+import org.exoplatform.services.jcr.datamodel.InternalQName;
 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.QPath;
 import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.Constants;
 import org.exoplatform.services.jcr.impl.core.lock.LockData;
 import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
+import org.exoplatform.services.jcr.impl.dataflow.ValueDataConvertor;
 import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
@@ -32,13 +36,17 @@
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Node;
 
+import java.io.IOException;
 import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemExistsException;
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.lock.LockException;
 
@@ -75,11 +83,12 @@
     * JBossCacheStorageConnection  constructor.
     *
     * @param cache Cache<Serializable, Object>
+    * @param refs 
     */
    public JBossCacheStorageConnection(Cache<Serializable, Object> cache, Node<Serializable, Object> nodesRoot,
-      Node<Serializable, Object> propsRoot, Node<Serializable, Object> locksRoot)
+      Node<Serializable, Object> propsRoot, Node<Serializable, Object> locksRoot, Node<Serializable, Object> refsRoot)
    {
-      super(nodesRoot, propsRoot, locksRoot);
+      super(nodesRoot, propsRoot, locksRoot, refsRoot);
 
       this.cache = cache;
    }
@@ -138,6 +147,43 @@
          throw new RepositoryException("Property's parent doesn't exist " + data.getQPath().getAsString());
       }
 
+      if (data.getType() == PropertyType.REFERENCE)
+      {
+         Fqn propUUID = makeNodeFqn(data.getIdentifier());
+
+         for (ValueData value : data.getValues())
+         {
+
+            String refNodeUUID;
+            try
+            {
+               refNodeUUID = ValueDataConvertor.readString(value);
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+            catch (IOException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+
+            Fqn refNode = makeNodeFqn(refNodeUUID);
+
+            // add to $REFS map
+            Node<Serializable, Object> refParent = refsRoot.getChild(refNode);
+            if (refParent == null)
+            {
+               refParent = refsRoot.addChild(refNode);
+            }
+
+            refParent.addChild(propUUID);
+         }
+
+      }
+
       // add to parent's properties attr
       String propName = data.getQPath().getName().getAsString();
       if (parent.get(propName) == null)
@@ -162,6 +208,23 @@
    {
       startBatch();
 
+      for (InternalQName mixin : data.getMixinTypeNames())
+      {
+         if (mixin.equals(Constants.MIX_REFERENCEABLE))
+         {
+            // check and release references
+            Node<Serializable, Object> node = refsRoot.addChild(Fqn.fromElements(data.getIdentifier()));
+            if (node != null)
+            {
+               if (node.getChildrenNames().size() != 0)
+               {
+                  throw new RepositoryException("Referenceable node removed but still have live references.");
+               }
+            }
+            break;
+         }
+      }
+
       if (data.getParentIdentifier() != null)
       {
          // check if parent is cached
@@ -199,6 +262,46 @@
          throw new RepositoryException("Property parent doesn't exist " + data.getQPath().getAsString());
       }
 
+      if (data.getType() == PropertyType.REFERENCE)
+      {
+         Fqn propUUID = makeNodeFqn(data.getIdentifier());
+
+         for (ValueData value : data.getValues())
+         {
+
+            String refNodeUUID;
+            try
+            {
+               refNodeUUID = ValueDataConvertor.readString(value);
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+            catch (IOException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+
+            // remove property from referencedNode in $REFS map
+
+            Node<Serializable, Object> refParent = refsRoot.getChild(makeNodeFqn(refNodeUUID));
+            if (refParent != null)
+            {
+               refParent.removeChild(propUUID);
+            }
+            // check is there is no more references
+            if (refParent.getChildrenNames().size() == 0)
+            {
+               //TODO remove children
+               refsRoot.removeChild(makeNodeFqn(refNodeUUID));
+            }
+         }
+
+      }
+
       // remove from parent's properties attr
       // TODO validate does deleted
       if (parent.remove(data.getQPath().getName().getAsString()) == null)
@@ -474,8 +577,33 @@
    public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
       IllegalStateException, UnsupportedOperationException
    {
-      // TODO refs impl
-      return new ArrayList<PropertyData>();
+      ArrayList<PropertyData> references = new ArrayList<PropertyData>();
+
+      Node<Serializable, Object> node = this.refsRoot.getChild(Fqn.fromElements(nodeIdentifier));
+      if (node != null)
+      {
+         Set<Object> props = node.getChildrenNames();
+
+         for (Object o : props)
+         {
+            String propUUID = (String)o;
+            Node<Serializable, Object> prop = propsRoot.getChild(Fqn.fromElements(propUUID));
+            if (prop == null)
+            {
+               throw new RepositoryException("FATAL Property record not found(" + propUUID
+                  + "), but listed in reference properties of node " + nodeIdentifier);
+            }
+
+            PropertyData propData = (PropertyData)prop.get(ITEM_DATA);
+            if (propData == null)
+            {
+               throw new RepositoryException("FATAL Property data is null. Property UUID " + propUUID);
+            }
+
+            references.add(propData);
+         }
+      }
+      return references;
    }
 
    /**
@@ -625,13 +753,107 @@
    {
       startBatch();
 
+      Fqn propFqn = Fqn.fromElements(data.getIdentifier());
+
       // update in PROPERTIES
-      Node<Serializable, Object> prop = propsRoot.getChild(makePropFqn(data.getIdentifier()));
+      Node<Serializable, Object> prop = propsRoot.getChild(propFqn);
       if (prop == null)
       {
          throw new IllegalStateException("Property was deleted " + data.getQPath().getAsString());
       }
 
+      if (data.getType() == PropertyType.REFERENCE)
+      {
+         PropertyData propData = (PropertyData)prop.get(ITEM_DATA);
+         if (propData == null)
+         {
+            throw new RepositoryException("FATAL Property data is null. Parent " + data.getQPath().getAsString());
+         }
+
+         //get Set of old values
+         Set<String> removeSet = new HashSet<String>();
+         for (ValueData value : propData.getValues())
+         {
+            try
+            {
+               removeSet.add(ValueDataConvertor.readString(value));
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+            catch (IOException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+         }
+
+         Set<String> addSet = new HashSet<String>();
+         // check new 
+         for (ValueData value : data.getValues())
+         {
+            try
+            {
+               addSet.add(ValueDataConvertor.readString(value));
+            }
+            catch (UnsupportedEncodingException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+            catch (IOException e)
+            {
+               // TODO Auto-generated catch block
+               throw new RepositoryException(e.getMessage(), e);
+            }
+         }
+
+         String[] added = new String[addSet.size()];
+         addSet.toArray(added);
+
+         for (String id : added)
+         {
+            if (removeSet.contains(id))
+            {
+               removeSet.remove(id);
+               addSet.remove(id);
+            }
+         }
+
+         // remove references to nodes
+         for (String id : removeSet)
+         {
+            Node<Serializable, Object> node = refsRoot.getChild(Fqn.fromElements(id));
+            if (!node.removeChild(propFqn))
+            {
+               throw new RepositoryException("FATAL Reference property was not removed from REFS table of node " + id);
+            }
+
+            // check node
+            if (node.getChildrenNames().size() == 0)
+            {
+               //TODO remove children
+               refsRoot.removeChild(Fqn.fromElements(id));
+            }
+         }
+
+         // add references to nodes
+         for (String id : addSet)
+         {
+            Fqn nodeFqn = Fqn.fromElements(id);
+            Node<Serializable, Object> node = refsRoot.getChild(nodeFqn);
+
+            if (node == null)
+            {
+               node = refsRoot.addChild(nodeFqn);
+            }
+            node.addChild(propFqn);
+         }
+      }
+
+      // remove
       prop.put(ITEM_DATA, data);
    }
 

Modified: jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheWorkspaceDataContainer.java
===================================================================
--- jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheWorkspaceDataContainer.java	2009-11-19 15:56:16 UTC (rev 781)
+++ jcr/branches/1.12.0-JBC/component/core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheWorkspaceDataContainer.java	2009-11-19 16:19:28 UTC (rev 782)
@@ -74,6 +74,8 @@
 
    private Node<Serializable, Object> locks;
 
+   private Node<Serializable, Object> refs;
+
    /**
     * JBossWorkspaceDataContainer  constructor.
     *
@@ -130,6 +132,7 @@
       this.nodes = cacheRoot.addChild(Fqn.fromElements(JBossCacheStorage.NODES));
       this.properties = cacheRoot.addChild(Fqn.fromElements(JBossCacheStorage.PROPS));
       this.locks = cacheRoot.addChild(Fqn.fromElements(JBossCacheStorage.LOCKS));
+      this.refs = cacheRoot.addChild(Fqn.fromElements(JBossCacheStorage.REFS));
       cache.endBatch(true);
    }
 
@@ -179,7 +182,7 @@
       //         throw new RepositoryException("Container is not started");
       //      }
 
-      return new JBossCacheStorageConnection(cache, nodes, properties, locks);
+      return new JBossCacheStorageConnection(cache, nodes, properties, locks, refs);
    }
 
    /**
@@ -193,7 +196,7 @@
       //         throw new RepositoryException("Container is not started");
       //      }
 
-      return new JBossCacheStorageConnection(cache, nodes, properties, locks);
+      return new JBossCacheStorageConnection(cache, nodes, properties, locks, refs);
    }
 
    /**

Modified: jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractJBossCacheStorageConnectionTest.java
===================================================================
--- jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractJBossCacheStorageConnectionTest.java	2009-11-19 15:56:16 UTC (rev 781)
+++ jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractJBossCacheStorageConnectionTest.java	2009-11-19 16:19:28 UTC (rev 782)
@@ -24,7 +24,6 @@
 import org.exoplatform.services.jcr.datamodel.QPath;
 import org.exoplatform.services.jcr.impl.Constants;
 import org.exoplatform.services.jcr.impl.storage.JDBCWorkspaceDataContainerTestBase;
-import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer;
 import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
 import org.jboss.cache.Cache;
 import org.jboss.cache.CacheSPI;
@@ -57,6 +56,8 @@
 
    protected Node<Serializable, Object> locks;
 
+   protected Node<Serializable, Object> refs;
+
    protected String jbcConfig;
 
    /**
@@ -84,9 +85,10 @@
       nodes = cacheRoot.addChild(Fqn.fromString(JBossCacheStorage.NODES));
       props = cacheRoot.addChild(Fqn.fromString(JBossCacheStorage.PROPS));
       locks = cacheRoot.addChild(Fqn.fromString(JBossCacheStorage.LOCKS));
+      refs = cacheRoot.addChild(Fqn.fromString(JBossCacheStorage.REFS));
       cache.endBatch(true);
       // JCR connection
-      conn = new JBossCacheStorageConnection(cache, nodes, props, locks);
+      conn = new JBossCacheStorageConnection(cache, nodes, props, locks, refs);
    }
 
    protected void initJBCConfig()
@@ -157,8 +159,8 @@
          Constants.DEFAULT_ENCODING));
    }
 
-   protected void checkChildProp(Node<Serializable, Object> node, InternalQName propName, String propId, QPath propPath,
-      Object propValue) throws UnsupportedEncodingException, IllegalStateException, IOException
+   protected void checkChildProp(Node<Serializable, Object> node, InternalQName propName, String propId,
+      QPath propPath, Object propValue) throws UnsupportedEncodingException, IllegalStateException, IOException
    {
       String pid = (String)node.get(propName.getAsString());
 
@@ -201,5 +203,5 @@
          assertEquals("Node persisted version wrong", version, childNodeData.getPersistedVersion());
       }
    }
-   
+
 }

Modified: jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnectionTest.java
===================================================================
--- jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnectionTest.java	2009-11-19 15:56:16 UTC (rev 781)
+++ jcr/branches/1.12.0-JBC/component/core/src/test/java/org/exoplatform/services/jcr/impl/storage/jbosscache/JBossCacheStorageConnectionTest.java	2009-11-19 16:19:28 UTC (rev 782)
@@ -24,8 +24,8 @@
 import org.exoplatform.services.jcr.datamodel.NodeData;
 import org.exoplatform.services.jcr.datamodel.PropertyData;
 import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.ValueData;
 import org.exoplatform.services.jcr.impl.Constants;
-import org.exoplatform.services.jcr.impl.core.lock.LockData;
 import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
 import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
 import org.exoplatform.services.jcr.impl.dataflow.TransientValueData;
@@ -33,11 +33,14 @@
 import org.jboss.cache.Node;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemExistsException;
 import javax.jcr.lock.LockException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
 
 /**
  * Created by The eXo Platform SAS.
@@ -635,13 +638,13 @@
       // add /jcr:system
       conn.add(new TransientNodeData(Constants.JCR_SYSTEM_PATH, Constants.SYSTEM_UUID, 1, Constants.NT_UNSTRUCTURED,
          new InternalQName[0], 0, Constants.ROOT_UUID, new AccessControlList()));
-      
-      
-      try {
+
+      try
+      {
          // add /jcr:system twice 
          conn.add(new TransientNodeData(Constants.JCR_SYSTEM_PATH, Constants.SYSTEM_UUID, 1, Constants.NT_UNSTRUCTURED,
-                  new InternalQName[0], 0, Constants.ROOT_UUID, new AccessControlList()));
-         
+            new InternalQName[0], 0, Constants.ROOT_UUID, new AccessControlList()));
+
          conn.commit();
          
          fail("The node jcr:system should not be save");
@@ -738,4 +741,98 @@
          //ok
       }
    }
+
+   public void testGetReferences() throws Exception
+   {
+      // add root (/)
+      conn.add(new TransientNodeData(Constants.ROOT_PATH, Constants.ROOT_UUID, 1, Constants.NT_UNSTRUCTURED,
+         new InternalQName[0], 0, null, new AccessControlList()));
+
+      // add refernceable node (/node)
+      String node1id = "1";
+      QPath node1path = QPath.parse("[]:1[]firstParent:1");
+
+      NodeData node1 =
+         new TransientNodeData(node1path, node1id, 1, Constants.NT_UNSTRUCTURED,
+            new InternalQName[]{Constants.MIX_REFERENCEABLE}, 0, Constants.ROOT_UUID, new AccessControlList());
+      conn.add(node1);
+
+      // add node2 with reference on node
+      String node2id = "2";
+      QPath node2path = QPath.parse("[]:1[]secondParent:1");
+      conn.add(new TransientNodeData(node2path, node2id, 1, Constants.NT_UNSTRUCTURED, new InternalQName[0], 0,
+         Constants.ROOT_UUID, new AccessControlList()));
+
+      String refpropid = "21";
+      TransientPropertyData prop =
+         new TransientPropertyData(QPath.makeChildPath(node2path, "[]refprop:1"), refpropid, 0, PropertyType.REFERENCE,
+            node2id, false);
+
+      prop.setValue(new TransientValueData(node1id));
+      conn.add(prop);
+
+      String node3id = "3";
+      QPath node3path = QPath.parse("[]:1[]node3:1");
+
+      NodeData node3 =
+         new TransientNodeData(node3path, node3id, 1, Constants.NT_UNSTRUCTURED,
+            new InternalQName[]{Constants.MIX_REFERENCEABLE}, 0, Constants.ROOT_UUID, new AccessControlList());
+      conn.add(node3);
+
+      // check in nodes
+      treePrint(nodes);
+
+      // get root node ([]:1)
+      Node<Serializable, Object> rootNode = nodes.getChild(Fqn.fromElements(Constants.ROOT_UUID));
+      assertNotNull("Node expected", rootNode);
+
+      // check root Node
+      checkNode(rootNode, Constants.ROOT_UUID, Constants.ROOT_PATH);
+
+      // cechk childs
+      assertEquals("Childs expected", 3, rootNode.getChildren().size());
+      checkChildNode(rootNode, node1id, node1path);
+      checkChildNode(rootNode, node2id, node2path);
+      checkChildNode(rootNode, node3id, node3path);
+
+      List<PropertyData> props = conn.getReferencesData(node1id);
+      assertEquals("References expected", 1, props.size());
+      props = conn.getReferencesData(node3id);
+      assertEquals("References expected", 0, props.size());
+
+      // try remove referenced  node
+      try
+      {
+         conn.delete(node1);
+         fail();
+      }
+      catch (RepositoryException e)
+      {
+         //ok
+      }
+
+      // update reference property
+
+      TransientPropertyData updateProp =
+         new TransientPropertyData(prop.getQPath(), prop.getIdentifier(), 0, PropertyType.REFERENCE, prop
+            .getParentIdentifier(), false);
+
+      List<ValueData> list = new ArrayList<ValueData>();
+      list.add(new TransientValueData(node1id));
+      list.add(new TransientValueData(node3id));
+
+      //  ValueData[]{new TransientValueData(node1id)}
+      updateProp.setValues(list);
+      conn.update(updateProp);
+
+      // check
+      props = conn.getReferencesData(node1id);
+      assertEquals("References expected", 1, props.size());
+      props = conn.getReferencesData(node3id);
+      assertEquals("References expected", 1, props.size());
+
+      conn.delete(updateProp);
+      conn.delete(node1);
+      conn.delete(node3);
+   }
 }



More information about the exo-jcr-commits mailing list