/* * 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.jcr2spi.nodetype; import java.util.Arrays; import java.util.List; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeDefinitionTemplate; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.nodetype.NodeTypeTemplate; import org.apache.jackrabbit.test.AbstractJCRTest; import org.apache.jackrabbit.test.NotExecutableException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <code>AddMixinTest</code>... */ public class AddMixinTest extends AbstractJCRTest { private static Logger log = LoggerFactory.getLogger(AddMixinTest.class); private NodeTypeManager ntMgr; @Override protected void setUp() throws Exception { super.setUp(); ntMgr = testRootNode.getSession().getWorkspace().getNodeTypeManager(); } @Override protected void tearDown() throws Exception { testRootNode.refresh(false); ntMgr = null; super.tearDown(); } /** * Implementation specific test for 'addMixin' only taking effect upon * save. * * @throws NotExecutableException * @throws RepositoryException */ public void testAddMixinToNewNode() throws NotExecutableException, RepositoryException { Node newNode; try { newNode = testRootNode.addNode(nodeName1, testNodeType); newNode.addMixin(mixReferenceable); } catch (RepositoryException e) { throw new NotExecutableException(); } assertFalse("Mixin must not be active before Node has been saved.", newNode.isNodeType(mixReferenceable)); NodeType[] mixins = newNode.getMixinNodeTypes(); for (int i = 0; i < mixins.length; i++) { if (mixins[i].getName().equals(testNodeType)) { fail("Mixin must not be active before Node has been saved."); } } } /** * Implementation specific test adding a new Node with a nodeType, that has * a mixin-supertype. The mixin must only take effect upon save. * * @throws NotExecutableException * @throws RepositoryException */ public void testImplicitMixinOnNewNode() throws NotExecutableException, RepositoryException { Node newNode; try { String ntResource = superuser.getNamespacePrefix(NS_NT_URI) + ":resource"; newNode = testRootNode.addNode(nodeName1, ntResource); } catch (RepositoryException e) { throw new NotExecutableException(); } assertFalse("Implict Mixin inherited by primary Nodetype must not be active before Node has been saved.", newNode.isNodeType(mixReferenceable)); NodeType[] mixins = newNode.getMixinNodeTypes(); for (int i = 0; i < mixins.length; i++) { if (mixins[i].getName().equals(testNodeType)) { fail("Implict Mixin inherited by primary Nodetype must not be active before Node has been saved."); } } } /** * Implementation specific test adding a new Node with a nodeType, that has * a mixin-supertype. The mixin must only take effect upon save. * * @throws NotExecutableException * @throws RepositoryException */ public void testAddMultipleAtOnce() throws NotExecutableException, RepositoryException { Node node; try { node = testRootNode.addNode(nodeName1, testNodeType); node.addMixin(mixReferenceable); node.addMixin(mixLockable); testRootNode.save(); } catch (RepositoryException e) { throw new NotExecutableException(); } assertTrue("Adding 2 mixins at once -> both must be present.", node.isNodeType(mixReferenceable) && node.isNodeType(mixLockable)); } /** * Implementation specific test adding a new Node with a nodeType, that has * a mixin-supertype. The mixin must only take effect upon save. * * @throws NotExecutableException * @throws RepositoryException */ public void testAddMultipleAtOnce2() throws NotExecutableException, RepositoryException { Node node; try { node = testRootNode.addNode(nodeName1, testNodeType); node.addMixin(mixReferenceable); node.addMixin(mixLockable); testRootNode.save(); } catch (RepositoryException e) { throw new NotExecutableException(); } List<NodeType> mixins = Arrays.asList(node.getMixinNodeTypes()); assertTrue("Adding 2 mixins at once -> both must be present.", mixins.contains(ntMgr.getNodeType(mixReferenceable)) && mixins.contains(ntMgr.getNodeType(mixLockable))); } /** * Implementation specific test adding a new Node with a nodeType, that has * a mixin-supertype. The mixin must only take effect upon save. * * @throws NotExecutableException * @throws RepositoryException */ public void testAddMultipleSeparately() throws NotExecutableException, RepositoryException { Node node; try { node = testRootNode.addNode(nodeName1, testNodeType); node.addMixin(mixReferenceable); testRootNode.save(); node.addMixin(mixLockable); testRootNode.save(); } catch (RepositoryException e) { throw new NotExecutableException(); } assertTrue("Adding 2 mixins at once -> both must be present.", node.isNodeType(mixReferenceable) && node.isNodeType(mixLockable)); List<NodeType> mixins = Arrays.asList(node.getMixinNodeTypes()); assertTrue("Adding 2 mixins at once -> both must be present.", mixins.contains(ntMgr.getNodeType(mixReferenceable)) && mixins.contains(ntMgr.getNodeType(mixLockable))); } public void testAddItemsDefinedByMixin() throws NotExecutableException, RepositoryException { // register mixin NodeTypeManager ntm = superuser.getWorkspace().getNodeTypeManager(); NodeTypeTemplate ntd = ntm.createNodeTypeTemplate(); ntd.setName("testMixin"); ntd.setMixin(true); NodeDefinitionTemplate nodeDef = ntm.createNodeDefinitionTemplate(); nodeDef.setName("child"); nodeDef.setRequiredPrimaryTypeNames(new String[] {"nt:folder"}); ntd.getNodeDefinitionTemplates().add(nodeDef); ntm.registerNodeType(ntd, true); // create node and add mixin Node node = testRootNode.addNode(nodeName1, "nt:resource"); node.setProperty("jcr:data", "abc"); node.addMixin("testMixin"); superuser.save(); // create a child node defined by the mixin node.addNode("child", "nt:folder"); node.save(); } public void testAddItemsDefinedByMixin2() throws NotExecutableException, RepositoryException { // register mixin NodeTypeManager ntm = superuser.getWorkspace().getNodeTypeManager(); NodeTypeTemplate ntd = ntm.createNodeTypeTemplate(); ntd.setName("testMixin"); ntd.setMixin(true); NodeDefinitionTemplate nodeDef = ntm.createNodeDefinitionTemplate(); nodeDef.setName("child"); nodeDef.setRequiredPrimaryTypeNames(new String[] {"nt:folder"}); ntd.getNodeDefinitionTemplates().add(nodeDef); ntm.registerNodeType(ntd, true); // create node and add mixin Node node = testRootNode.addNode(nodeName1, "nt:resource"); node.setProperty("jcr:data", "abc"); node.addMixin("testMixin"); superuser.save(); // create a child node defined by the mixin without specifying the // node type try { node.addNode("child"); fail(); } catch (ConstraintViolationException e) { // success as ChildNode Definition doesn't specify a default primary // type -> see comment in ItemDefinitionProvider#getQNodeDefinition } } public void testAddItemsDefinedByMixin3() throws NotExecutableException, RepositoryException { // register mixin NodeTypeManager ntm = superuser.getWorkspace().getNodeTypeManager(); NodeTypeTemplate ntd = ntm.createNodeTypeTemplate(); ntd.setName("testMixin"); ntd.setMixin(true); NodeDefinitionTemplate nodeDef = ntm.createNodeDefinitionTemplate(); nodeDef.setName("child"); nodeDef.setRequiredPrimaryTypeNames(new String[] {"nt:folder"}); nodeDef.setDefaultPrimaryTypeName("nt:folder"); ntd.getNodeDefinitionTemplates().add(nodeDef); ntm.registerNodeType(ntd, true); // create node and add mixin Node node = testRootNode.addNode(nodeName1, "nt:resource"); node.setProperty("jcr:data", "abc"); node.addMixin("testMixin"); superuser.save(); // create a child node defined by the mixin without specifying the // node type -> must succeed since default primary type is specified // in the child node def Node c = node.addNode("child"); assertEquals("nt:folder", c.getPrimaryNodeType().getName()); superuser.save(); } }