[dna-commits] DNA SVN: r1058 - in trunk: dna-jcr/src/main/java/org/jboss/dna/jcr and 2 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Sat Jun 20 20:45:14 EDT 2009


Author: bcarothers
Date: 2009-06-20 20:45:14 -0400 (Sat, 20 Jun 2009)
New Revision: 1058

Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SetPropertyRequest.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
   trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
Log:
DNA-370 JcrWorkspace.clone Is Not Implemented

Committed patch to add constraint checking to clone with removeExisting = true. 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SetPropertyRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SetPropertyRequest.java	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SetPropertyRequest.java	2009-06-21 00:45:14 UTC (rev 1058)
@@ -23,6 +23,7 @@
  */
 package org.jboss.dna.graph.request;
 
+import java.util.Arrays;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.HashCode;
 import org.jboss.dna.graph.GraphI18n;
@@ -209,6 +210,6 @@
     @Override
     public String toString() {
         return "set property " + property().getName() + " on " + on() + " in the \"" + workspaceName + "\" workspace to "
-               + property().getValuesAsArray();
+               + Arrays.asList(property().getValuesAsArray()).toString();
     }
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java	2009-06-21 00:45:14 UTC (rev 1058)
@@ -89,6 +89,7 @@
     public static I18n unableToSetSingleValuedPropertyUsingMultipleValues;
     public static I18n unableToRefreshBranchSinceAtLeastOneNodeMovedToParentOutsideOfBranch;
     public static I18n allPropertyValuesMustHaveSameType;
+    public static I18n cannotRemoveNodeFromClone;
 
     public static I18n unableToRemoveRootNode;
     public static I18n unableToMoveNodeToBeChildOfDecendent;

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java	2009-06-21 00:45:14 UTC (rev 1058)
@@ -24,6 +24,7 @@
 package org.jboss.dna.jcr;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -113,7 +114,7 @@
                  boolean mixin,
                  boolean orderableChildNodes ) {
         assert context != null;
-        
+
         this.context = context;
         this.nodeTypeManager = nodeTypeManager;
         this.name = name;
@@ -140,12 +141,12 @@
             JcrNodeType superType = thisAndAllSupertypes.get(i);
             for (NodeType superSuperType : superType.getDeclaredSupertypes()) {
                 JcrNodeType jcrSuperSuperType = (JcrNodeType)superSuperType;
-                
+
                 if (jcrSuperSuperType == null) {
                     assert JcrNtLexicon.BASE.equals(name);
                     continue;
                 }
-                
+
                 if (typeNames.add(jcrSuperSuperType.getInternalName())) {
                     thisAndAllSupertypes.add(jcrSuperSuperType);
                 }
@@ -208,6 +209,17 @@
         return allDefinitions.allChildNodeDefinitions(childName);
     }
 
+    JcrNodeDefinition childNodeDefinition( NodeDefinitionId nodeDefnId ) {
+        List<Name> requiredPrimaryTypeNames = Arrays.asList(nodeDefnId.getRequiredPrimaryTypes());
+        for (JcrNodeDefinition nodeDefn : allChildNodeDefinitions(nodeDefnId.getChildDefinitionName())) {
+            if (nodeDefn.getRequiredPrimaryTypeNames().size() == requiredPrimaryTypeNames.size()
+                && nodeDefn.getRequiredPrimaryTypeNames().containsAll(requiredPrimaryTypeNames)) {
+                return nodeDefn;
+            }
+        }
+        return null;
+    }
+
     /**
      * {@inheritDoc}
      * 

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java	2009-06-21 00:45:14 UTC (rev 1058)
@@ -26,12 +26,15 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.AccessControlException;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.InvalidSerializedDataException;
 import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.NoSuchWorkspaceException;
 import javax.jcr.PathNotFoundException;
@@ -50,6 +53,8 @@
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.SubgraphNode;
 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connector.RepositorySource;
 import org.jboss.dna.graph.connector.RepositorySourceException;
@@ -60,8 +65,10 @@
 import org.jboss.dna.graph.property.PathFactory;
 import org.jboss.dna.graph.property.Property;
 import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.UuidFactory;
 import org.jboss.dna.graph.property.ValueFormatException;
 import org.jboss.dna.graph.property.basic.GraphNamespaceRegistry;
+import org.jboss.dna.graph.request.ReadBranchRequest;
 import org.jboss.dna.jcr.JcrContentHandler.EnclosingSAXException;
 import org.jboss.dna.jcr.JcrContentHandler.SaveMode;
 import org.jboss.dna.jcr.JcrRepository.Option;
@@ -308,12 +315,20 @@
         Name newNodeName = destPath.getLastSegment().getName();
         String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
 
+        Subgraph sourceTree = null;
         // This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
         graph.useWorkspace(srcWorkspace);
         Property primaryTypeProp;
         Property uuidProp;
         try {
-            Map<Name, Property> props = graph.getNodeAt(srcPath).getPropertiesByName();
+            Map<Name, Property> props;
+
+            if (removeExisting) {
+                sourceTree = graph.getSubgraphOfDepth(ReadBranchRequest.NO_MAXIMUM_DEPTH).at(srcPath);
+                props = sourceTree.getRoot().getPropertiesByName();
+            } else {
+                props = graph.getNodeAt(srcPath).getPropertiesByName();
+            }
             primaryTypeProp = props.get(JcrLexicon.PRIMARY_TYPE);
             uuidProp = props.get(DnaLexicon.UUID);
         } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
@@ -331,12 +346,56 @@
                                                     newNodeName,
                                                     nameFactory.create(primaryTypeProp.getFirstValue()));
 
-        // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
-        // graph.copy(srcPath).fromWorkspace(srcWorkspace).to(destPath);
         if (removeExisting) {
+            assert sourceTree != null;
+
+            // Find all of the UUIDS in the source tree
+            UuidFactory uuidFactory = context().getValueFactories().getUuidFactory();
+            PathFactory pathFactory = context().getValueFactories().getPathFactory();
+
+            Set<UUID> sourceUuids = new HashSet<UUID>();
+            LinkedList<SubgraphNode> nodesToVisit = new LinkedList<SubgraphNode>();
+            nodesToVisit.push(sourceTree.getRoot());
+
+            while (!nodesToVisit.isEmpty()) {
+                SubgraphNode node = nodesToVisit.pop();
+
+                UUID uuid = uuidFactory.create(node.getProperty(DnaLexicon.UUID).getFirstValue().toString());
+                if (uuid != null) {
+                    sourceUuids.add(uuid);
+                }
+                for (Path.Segment childSegment : node.getChildrenSegments()) {
+                    nodesToVisit.add(node.getNode(pathFactory.createRelativePath(childSegment)));
+                }
+            }
+
+            // See if the nodes exist in the current workspace outside of the current tree
+            for (UUID uuid : sourceUuids) {
+                NodeInfo nodeInfo = null;
+                try {
+                    nodeInfo = session.cache().findNodeInfo(uuid);
+                } catch (ItemNotFoundException infe) {
+                    continue;
+                }
+                assert nodeInfo != null;
+
+                NodeDefinitionId nodeDefnId = nodeInfo.getDefinitionId();
+
+                JcrNodeType nodeType = nodeTypeManager.getNodeType(nodeDefnId.getNodeTypeName());
+                JcrNodeDefinition nodeDefn = nodeType.childNodeDefinition(nodeDefnId);
+                if (nodeDefn.isMandatory()) {
+                    // We can't just remove a mandatory node... unless its parent will be removed too!
+                    String path = session.cache().getPathFor(nodeInfo).getString(context().getNamespaceRegistry());
+                    throw new ConstraintViolationException(JcrI18n.cannotRemoveNodeFromClone.text(path, uuid));
+
+                }
+            }
+
+            // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
             graph.copy(srcPath).replacingExistingNodesWithSameUuids().fromWorkspace(srcWorkspace).to(destPath);
         } else {
             try {
+                // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
                 graph.copy(srcPath).failingIfUuidsMatch().fromWorkspace(srcWorkspace).to(destPath);
             } catch (UuidAlreadyExistsException uaee) {
                 throw new ItemExistsException(uaee.getMessage());

Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties	2009-06-21 00:45:14 UTC (rev 1058)
@@ -79,6 +79,7 @@
 unableToSetSingleValuedPropertyUsingMultipleValues = Unable to set existing single-valued property "{0}" on node "{1}" in workspace "{2}" using multi-value setter methods
 unableToRefreshBranchSinceAtLeastOneNodeMovedToParentOutsideOfBranch = Unable to refresh "{0}" in workspace "{2}" because at least one of its decendants was moved to another node outside of the branch that is not being refreshed 
 allPropertyValuesMustHaveSameType = All values of property "{0}" on node "{3}" in workspace "{4}" must all be {2} values (values were: {1})
+cannotRemoveNodeFromClone = The node at "{0}" with UUID "{1}" exists in the current workspace but cannot be removed because it is a mandatory child node
 
 unableToRemoveRootNode = Unable to remove the root node in workspace "{1}"
 unableToMoveNodeToBeChildOfDecendent = Node "{0}" in workspace "{2}" cannot be moved under a decendant node ("{1}") 

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java	2009-06-21 00:16:03 UTC (rev 1057)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java	2009-06-21 00:45:14 UTC (rev 1058)
@@ -1,5 +1,7 @@
 package org.jboss.dna.jcr;
 
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Credentials;
 import javax.jcr.Node;
@@ -8,6 +10,7 @@
 import javax.jcr.Property;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.nodetype.ConstraintViolationException;
 import org.apache.jackrabbit.test.AbstractJCRTest;
 
 /**
@@ -197,4 +200,74 @@
 
         assertNotNull(node4node1node2);
     }
+
+    /**
+     * A clone operation with removeExisting = true should fail if it would require removing an existing node that is a mandatory
+     * child node of some other parent (and not replacing it as part of the clone operation).
+     * 
+     * @throws Exception if an error occurs
+     */
+    public void testShouldNotCloneIfItWouldViolateTypeSemantics() throws Exception {
+        session = helper.getSuperuserSession("otherWorkspace");
+        assertThat(session.getWorkspace().getName(), is("otherWorkspace"));
+
+        String nodetype1 = this.getProperty("nodetype");
+        Node node1 = session.getRootNode().addNode("cloneSource", nodetype1);
+        // This node is not a mandatory child of nodetype1 (dnatest:referenceableUnstructured)
+        node1.addNode("dnatest:mandatoryChild", nodetype1);
+
+        session.save();
+        session.logout();
+
+        // /node4 in the default workspace is type dna:referenceableUnstructured
+        superuser.getRootNode().addNode("cloneTarget", nodetype1);
+
+        // /node3 in the default workspace is type dna:referenceableUnstructured
+        superuser.getRootNode().addNode(nodeName3, nodetype1);
+        superuser.save();
+
+        // Throw the cloned items under node4
+        superuser.getWorkspace().clone("otherWorkspace", "/cloneSource", "/cloneTarget/cloneSource", false);
+
+        superuser.refresh(false);
+        Node node3 = (Node)superuser.getItem("/node3");
+        assertThat(node3.getNodes().getSize(), is(0L));
+
+        Node node4node1 = (Node)superuser.getItem("/cloneTarget/cloneSource");
+        assertThat(node4node1.getNodes().getSize(), is(1L));
+
+        // Now clone from the same source under node3 and remove the existing records
+        superuser.getWorkspace().clone("otherWorkspace", "/cloneSource", "/" + nodeName3 + "/cloneSource", true);
+        superuser.refresh(false);
+
+        Node node3node1 = (Node)superuser.getItem("/node3/cloneSource");
+        assertThat(node3node1.getNodes().getSize(), is(1L));
+
+        // Check that the nodes were indeed removed
+        Node node4 = (Node)superuser.getItem("/cloneTarget");
+
+        assertThat(node4.getNodes().getSize(), is(0L));
+
+        superuser.getRootNode().addNode("nodeWithMandatoryChild", "dnatest:nodeWithMandatoryChild");
+        try {
+            superuser.save();
+            fail("A node with type dnatest:nodeWithMandatoryChild should not be savable until the child is added");
+        } catch (ConstraintViolationException cve) {
+            // Expected
+        }
+
+        superuser.move("/node3/cloneSource/dnatest:mandatoryChild", "/nodeWithMandatoryChild/dnatest:mandatoryChild");
+        superuser.save();
+        superuser.refresh(false);
+
+        // Now clone from the same source under node3 and remove the existing records
+        try {
+            superuser.getWorkspace().clone("otherWorkspace", "/cloneSource", "/" + nodeName3 + "/cloneSource", true);
+            fail("Should not be able to use clone to remove the mandatory child node at /nodeWithMandatoryChild/dnatest:mandatoryChild");
+        } catch (ConstraintViolationException cve) {
+            // expected
+        }
+
+    }
+
 }




More information about the dna-commits mailing list