You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by cl...@apache.org on 2007/08/17 00:06:05 UTC

svn commit: r566872 - in /jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src: main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/ test/java/org/apache/jackrabbit/ocm/manager/proxy/ test/java/org/apache/jackrabbit/ocm/test...

Author: clombart
Date: Thu Aug 16 15:06:04 2007
New Revision: 566872

URL: http://svn.apache.org/viewvc?view=rev&rev=566872
Log:
Apply and modify patch for JCR-1053. Thanks to André Bierwolf.
I added more unit tests on collection & proxy. 

Added:
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTDetail.java
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTMain.java
Modified:
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/NTCollectionConverterImpl.java
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/manager/proxy/ProxyTest.java
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/jcrmapping-proxy.xml
    jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/nodetypes/custom_nodetypes.xml

Modified: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/NTCollectionConverterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/NTCollectionConverterImpl.java?view=diff&rev=566872&r1=566871&r2=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/NTCollectionConverterImpl.java (original)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/NTCollectionConverterImpl.java Thu Aug 16 15:06:04 2007
@@ -33,6 +33,9 @@
 import javax.jcr.ValueFormatException;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
 import javax.jcr.version.VersionException;
 
 import org.apache.commons.logging.Log;
@@ -44,14 +47,19 @@
 import org.apache.jackrabbit.ocm.mapper.model.ClassDescriptor;
 import org.apache.jackrabbit.ocm.mapper.model.CollectionDescriptor;
 import org.apache.jackrabbit.ocm.reflection.ReflectionUtils;
+import org.apache.jackrabbit.util.ISO9075;
 
 /**
  * Collection Mapping/convertion based on node type.
  *
- * This collection mapping strategy maps a collection into several nodes based on specific node type.
+ * This collection mapping strategy maps the collection elements into subnodes based on the same node types.
+ * 
+ * There are 2 constraints in this collection converter : 
+ * 1/ this is not possible to have 2 different collections in the main object which are used the same jcr node type for their elements. 
+ * 2/ this is not possible to make a distinction between an empty collection and an null collection. 
  *
  *
- * If the collection element class contains an id (see the FieldDescriptor definition), this id value is used to build the collection element node.
+ * If the collection element class contains an id (see the FieldDescriptor definition), this id value is used to build the collection element node name.
  * Otherwise, the element node name is a simple constant (collection-element)
  *
  * Example - without an id attribute:
@@ -61,6 +69,8 @@
  *                ....
  *          /collection-element (node used to store the second collection element)
  *          ...
+ *          
+ *          Each "collection-element" nodes have the same jcr node type
  *
  * Example - with an id attribute:
  *   /test (Main object containing the collection field )
@@ -69,6 +79,8 @@
  *                ....
  *          /anotherValue (id value assigned to the first element)
  *          ...
+ *          
+ *          Each collection element nodes have the same jcr node type
  *
  * @author <a href="mailto:christophe.lombart@gmail.com">Christophe Lombart</a>
  *
@@ -174,13 +186,13 @@
         }
 
         // Delete JCR nodes that are not present in the collection
-         Collection collectionNodes = this.getCollectionNodes(session, parentNode, 
+         NodeIterator nodes = this.getCollectionNodes(session, parentNode, 
         		                                              elementClassDescriptor.getJcrType());
-         if (collectionNodes != null && elementClassDescriptor.hasIdField()) {
-            Iterator nodeIterator = collectionNodes.iterator();
+         if (nodes != null && elementClassDescriptor.hasIdField()) {
+            
 
-            while (nodeIterator.hasNext()) {
-                Node child = (Node) nodeIterator.next();
+            while (nodes.hasNext()) {
+                Node child = (Node) nodes.next();
                 
                 if (!updatedItems.containsKey(child.getName())) {
                     child.remove();
@@ -198,17 +210,16 @@
                                                    Class collectionFieldClass) throws RepositoryException {
 	    ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass( ReflectionUtils.forName(collectionDescriptor.getElementClassName())); 
         ManageableCollection collection = ManageableCollectionUtil.getManageableCollection(collectionFieldClass);
-        //Class elementClass = ReflectionUtils.forName(collectionDescriptor.getElementClassName());
-        Collection nodes = this.getCollectionNodes(session, parentNode, elementClassDescriptor.getJcrType());
+
+        NodeIterator nodes = this.getCollectionNodes(session, parentNode, elementClassDescriptor.getJcrType());
         
-        if (nodes == null)
+        if (nodes == null || nodes.getSize() == 0)
         {
         	return null;
         }
-        
-        Iterator children = nodes.iterator();
-        while (children.hasNext()) {
-            Node itemNode = (Node) children.next();
+                
+        while (nodes.hasNext()) {
+            Node itemNode = (Node) nodes.next();
             log.debug("Collection node found : " + itemNode.getPath());
             Object item = objectConverter.getObject(session,  itemNode.getPath());
             collection.addObject(item);
@@ -219,54 +230,29 @@
     
     /**
      * @see AbstractCollectionConverterImpl#doIsNull(Session, Node, CollectionDescriptor, Class)
+     * 
+     * return true If the parent node doesn't contains node based on the node type associated to the collection elements
+     *  
      */
     protected boolean doIsNull(Session session,
                                               Node parentNode,
                                               CollectionDescriptor collectionDescriptor,
                                               Class collectionFieldClass) throws RepositoryException {
 
-    	    // This collection converter returns at least a empty collection (see in doGetCollection) 
-        return false;
-    }         
-
-    private Collection getCollectionNodes(Session session, Node parentNode, String itemNodeType)
+        String elementClassName = collectionDescriptor.getElementClassName();
+        ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass(ReflectionUtils.forName(elementClassName));
+		QueryResult queryResult = getQuery(session, parentNode, elementClassDescriptor.getJcrType());    	
+    	return queryResult.getNodes().getSize() == 0;
+    }
+        
+    private NodeIterator getCollectionNodes(Session session, Node parentNode, String itemNodeType)
     throws PathNotFoundException, ValueFormatException, RepositoryException {
 
-        List collectionNodes = new ArrayList();
-
-        // TODO : review this workaround used to support version nodes
-        // Searching on the version storage has some bugs => loop on all child noded and check the property jcr:frozenPrimaryType
-        // I have to investigate in more detail what's happen exactly
-        if (!parentNode.getPath().startsWith("/jcr:system/jcr:versionStorage")) {
-            NodeIterator nodeIterator = parentNode.getNodes();
-            while (nodeIterator.hasNext()) {
-                Node child = nodeIterator.nextNode();
-
-                if (child.isNodeType(itemNodeType)) {
-                    collectionNodes.add(child);
-                }
-            }
-        }
-        else {
-            NodeIterator nodeIterator = parentNode.getNodes();
-            while (nodeIterator.hasNext()) {
-                Node child = nodeIterator.nextNode();
-
-                if (child.getProperty("jcr:frozenPrimaryType").getString().equals(itemNodeType)) {
-                    collectionNodes.add(child);
-                }
-            }
-
-        }
-
-        if (collectionNodes.size() == 0)
-        {
-        	return null; 
-        }
-        else
-        {
-            return collectionNodes;
-        }
+        List collectionNodes = null;
+        
+        QueryResult queryResult = getQuery(session, parentNode, itemNodeType);
+        return  queryResult.getNodes();
+        
     }
 
     private void deleteCollectionItems(Session session, Node parentNode, String itemNodeType) 
@@ -277,13 +263,35 @@
            ValueFormatException, 
            RepositoryException
     {
-        Collection nodes = this.getCollectionNodes(session, parentNode, itemNodeType);
-        if (nodes == null) return;
-        	
-        Iterator nodeIterator = nodes.iterator();
-        while (nodeIterator.hasNext()) {
-            Node node = (Node) nodeIterator.next();
+        NodeIterator nodes = this.getCollectionNodes(session, parentNode, itemNodeType);
+        if (nodes == null || nodes.getSize()==0) return;
+        
+        while (nodes.hasNext()) {
+            Node node = (Node) nodes.next();
             node.remove();
         }
     }
+    
+   
+	
+	private QueryResult getQuery(Session session, Node parentNode, String jcrNodeType) throws RepositoryException, InvalidQueryException {
+    	String jcrExpression= "";    	
+    	if (!parentNode.getPath().startsWith("/jcr:system/jcr:versionStorage")) 
+    	{
+            jcrExpression = "SELECT * FROM " + jcrNodeType + " WHERE jcr:path LIKE '" + parentNode.getPath() 
+                                       + "/%' AND NOT jcr:path LIKE '" + parentNode.getPath() + "/%/%'";
+    	}
+    	else
+    	{
+    	
+    		jcrExpression = "SELECT * FROM nt:frozenNode" + " WHERE jcr:path LIKE '" + parentNode.getPath() + "/%'" 
+    		                 + " AND NOT jcr:path LIKE '" + parentNode.getPath() + "/%/%'"
+    		                 + " AND jcr:frozenPrimaryType = '" + jcrNodeType + "'";
+
+    		                
+    	}
+        Query jcrQuery = session.getWorkspace().getQueryManager().createQuery(jcrExpression, javax.jcr.query.Query.SQL);
+        QueryResult queryResult = jcrQuery.execute();
+		return queryResult;
+	}
 }

Modified: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/manager/proxy/ProxyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/manager/proxy/ProxyTest.java?view=diff&rev=566872&r1=566871&r2=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/manager/proxy/ProxyTest.java (original)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/manager/proxy/ProxyTest.java Thu Aug 16 15:06:04 2007
@@ -29,6 +29,7 @@
 import org.apache.jackrabbit.ocm.manager.ObjectContentManager;
 import org.apache.jackrabbit.ocm.testmodel.proxy.Detail;
 import org.apache.jackrabbit.ocm.testmodel.proxy.Main;
+import org.apache.jackrabbit.ocm.testmodel.proxy.NTMain;
 
 /**
  * Test inheritance with node type per concrete class (without  discreminator field)
@@ -114,7 +115,6 @@
 			//---------------------------------------------------------------------------------------------------------
 			// Retrieve the main object
 			//---------------------------------------------------------------------------------------------------------						
-
 			main = (Main) ocm.getObject( "/test");
 			assertNotNull("detail is null", main.getDetail());
 			assertTrue("Invalid detail bean", main.getDetail().getField().equals("AnotherFieldValue"));
@@ -126,6 +126,11 @@
 						
 			assertNull("nulldetail is not  null",main.getNullDetail());
 				
+			//---------------------------------------------------------------------------------------------------------
+			// Delete the main object
+			//---------------------------------------------------------------------------------------------------------						
+			ocm.remove("/test");
+			ocm.save();
 	
 		} catch (Exception e) {
 			e.printStackTrace();
@@ -135,7 +140,7 @@
 		
 	}
 	
-	public void testCollectionProxy() {
+	public void testDefaultCollectionConverterWithProxy() {
 
 		try {
 			ObjectContentManager ocm = this.getObjectContentManager();
@@ -183,7 +188,12 @@
 			assertNotNull("main  is null", main);
             assertEquals("Invalide size",main.getProxyCollection().size(), 101);
             assertNull("nullcollectionproxy  is not null", main.getNullProxyCollection());
-            
+
+            //---------------------------------------------------------------------------------------------------------
+			// Delete the main object
+			//---------------------------------------------------------------------------------------------------------						
+			ocm.remove("/test");
+			ocm.save();            
 	
 		} catch (Exception e) {
 			e.printStackTrace();
@@ -193,6 +203,82 @@
 		
 	}
 
+	public void testNTCollectionconverterWithProxy() {
+
+		try {
+
+			ObjectContentManager ocm = this.getObjectContentManager();			
+			
+			NTMain main = new NTMain();
+			main.setPath("/test");							
+            ocm.insert(main);
+			ocm.save();
+			
+			//---------------------------------------------------------------------------------------------------------
+			// Retrieve the main object
+			//---------------------------------------------------------------------------------------------------------						
+			main = (NTMain) ocm.getObject( "/test");
+			assertNotNull("main is null", main);
+
+            Collection result = main.getProxyCollection();
+            assertNull("Collection is not null", result);
+            
+/*			
+			//---------------------------------------------------------------------------------------------------------
+			// Update  
+			//---------------------------------------------------------------------------------------------------------
+			ArrayList  details= new ArrayList();
+			for(int i=1; i<=100;i++)
+			{
+				Detail detail = new Detail();
+				detail.setField("field" + i);				
+				details.add(detail);
+			}
+			main.setProxyCollection(details);
+			ocm.update(main);
+			ocm.save();
+            
+			//---------------------------------------------------------------------------------------------------------
+			// Retrieve the main object
+			//---------------------------------------------------------------------------------------------------------						
+			main = (NtMain) ocm.getObject( "/test");
+			assertNotNull("main is null", main);
+
+            result = main.getProxyCollection();
+            assertEquals("Invalide size", result.size(), 100);
+            
+			
+			//---------------------------------------------------------------------------------------------------------
+			// Update  
+			//---------------------------------------------------------------------------------------------------------            
+            Detail detail = new Detail();
+			detail.setField("newFieldValue");			
+			result.add(detail);
+			main.setProxyCollection(result);
+			ocm.update(main);
+			ocm.save();
+
+			//---------------------------------------------------------------------------------------------------------
+			// Retrieve the main object
+			//---------------------------------------------------------------------------------------------------------						
+			main = (NtMain) ocm.getObject("/test");
+			assertNotNull("main  is null", main);
+            assertEquals("Invalide size",main.getProxyCollection().size(), 101);
+            
+*/
+            //---------------------------------------------------------------------------------------------------------
+			// Delete the main object
+			//---------------------------------------------------------------------------------------------------------						
+			ocm.remove("/test");
+			ocm.save();            
+	
+		} catch (Exception e) {
+			e.printStackTrace();
+			fail();
+		}
+
+		
+	}
 
 
 	    

Added: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTDetail.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTDetail.java?view=auto&rev=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTDetail.java (added)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTDetail.java Thu Aug 16 15:06:04 2007
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.ocm.testmodel.proxy;
+
+public class NTDetail 
+{
+    private String path;
+	private String field;
+
+    
+	public String getPath() {
+		return path;
+	}
+
+	public void setPath(String path) {
+		this.path = path;
+	}
+	
+	public String getField() {
+		return field;
+	}
+
+	public void setField(String field) {
+		this.field = field;
+	} 
+    
+    
+}

Added: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTMain.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTMain.java?view=auto&rev=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTMain.java (added)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/java/org/apache/jackrabbit/ocm/testmodel/proxy/NTMain.java Thu Aug 16 15:06:04 2007
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.ocm.testmodel.proxy;
+
+import java.util.Collection;
+
+public class NTMain 
+{
+
+	private String path;
+	//private Detail proxyDetail;
+    private Collection proxyCollection;
+
+
+     
+	public String getPath() {
+		return path;
+	}
+
+	public void setPath(String path) {
+		this.path = path;
+	}
+
+	public Collection getProxyCollection() {
+		return proxyCollection;
+	}
+
+	public void setProxyCollection(Collection proxyCollection) {
+		this.proxyCollection = proxyCollection;
+	}
+
+     
+}

Modified: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/jcrmapping-proxy.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/jcrmapping-proxy.xml?view=diff&rev=566872&r1=566871&r2=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/jcrmapping-proxy.xml (original)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/jcrmapping-proxy.xml Thu Aug 16 15:06:04 2007
@@ -20,6 +20,21 @@
 		<field-descriptor fieldName="path" path="true" />
 		<field-descriptor fieldName="field" jcrName="field" />
 	</class-descriptor>
+	
+	<class-descriptor className="org.apache.jackrabbit.ocm.testmodel.proxy.NTDetail" jcrType="ocm:ntdetail" >		
+		<field-descriptor fieldName="path" path="true" />
+		<field-descriptor fieldName="field" jcrName="ocm:field" />
+	</class-descriptor>	
+		
+	<class-descriptor className="org.apache.jackrabbit.ocm.testmodel.proxy.NTMain" 	jcrType="ocm:ntmain"  >		
+		<field-descriptor fieldName="path" path="true" />
+		<!--  bean-descriptor fieldName="nullDetail" jcrName="nulldetail" proxy="true" jcrType="ocm:ntdetail" / -->		
+
+		<collection-descriptor fieldName="proxyCollection" proxy="true" 
+		                       elementClassName="org.apache.jackrabbit.ocm.testmodel.proxy.NTDetail" 
+		                       collectionConverter="org.apache.jackrabbit.ocm.manager.collectionconverter.impl.NTCollectionConverterImpl" />		
+	</class-descriptor>
+
+
 	
-</jackrabbit-ocm>
- 
+</jackrabbit-ocm>

Modified: jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/nodetypes/custom_nodetypes.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/nodetypes/custom_nodetypes.xml?view=diff&rev=566872&r1=566871&r2=566872
==============================================================================
--- jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/nodetypes/custom_nodetypes.xml (original)
+++ jackrabbit/trunk/contrib/jackrabbit-jcr-mapping/jcr-mapping/src/test/test-config/nodetypes/custom_nodetypes.xml Thu Aug 16 15:06:04 2007
@@ -221,5 +221,26 @@
             </defaultValues>     
      </propertyDefinition>
    </nodeType> 
+   
+  <nodeType name="ocm:ntdetail" isMixin="false" hasOrderableChildNodes="false" primaryItemName="">
+    <supertypes>
+      <supertype>nt:base</supertype>
+    </supertypes>
+    <propertyDefinition name="*" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false" />
+    <propertyDefinition name="ocm:field" requiredType="String" autoCreated="false" mandatory="true" onParentVersion="COPY" protected="false" multiple="false" />
+  </nodeType>
+  
+  <nodeType name="ocm:ntmain" isMixin="false" hasOrderableChildNodes="false" primaryItemName="">
+    <supertypes>
+      <supertype>nt:base</supertype>
+    </supertypes>
+    <propertyDefinition name="*" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false" />
+    <childNodeDefinition name="*" defaultPrimaryType="ocm:ntdetail" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" sameNameSiblings="true">
+      <requiredPrimaryTypes>
+        <requiredPrimaryType>ocm:ntdetail</requiredPrimaryType>
+      </requiredPrimaryTypes>
+    </childNodeDefinition>    
+  </nodeType>
+   
 </nodeTypes>