/* * ModeShape (http://www.modeshape.org) * * Licensed 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.modeshape.jcr; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Iterator; import java.util.List; import javax.jcr.Node; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeTemplate; import javax.jcr.nodetype.PropertyDefinitionTemplate; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.modeshape.common.FixFor; import org.modeshape.jcr.value.ValueFormatException; public class JcrNodeTypeManagerTest extends MultiUseAbstractTest { private static final String MIXIN1 = "mix:lockable"; private static final String MIXIN2 = "mix:referenceable"; private static final String[] MIXINS = new String[] { MIXIN1, MIXIN2 }; private static final String HIERARCHY_NODE_TYPE = "nt:hierarchyNode"; private static final String NT_FILE_NODE_TYPE = "nt:file"; private static final String NT_FOLDER_NODE_TYPE = "nt:folder"; private static final String SUBTYPE1 = NT_FILE_NODE_TYPE; // subtype of HIERARCHY_NODE_TYPE private static final String SUBTYPE2 = NT_FOLDER_NODE_TYPE; // subtype of HIERARCHY_NODE_TYPE private static final String[] SUBTYPES = new String[] { SUBTYPE1, SUBTYPE2 }; private static final String NO_MATCH_TYPE = "nt:query"; private static final String[] SUBTYPES_MIXINS; static { SUBTYPES_MIXINS = new String[SUBTYPES.length + MIXINS.length]; System.arraycopy(SUBTYPES, 0, SUBTYPES_MIXINS, 0, SUBTYPES.length); System.arraycopy(MIXINS, 0, SUBTYPES_MIXINS, SUBTYPES.length, MIXINS.length); } @BeforeClass public static final void beforeAll() throws Exception { MultiUseAbstractTest.beforeAll(); } @AfterClass public static final void afterAll() throws Exception { MultiUseAbstractTest.afterAll(); } private JcrNodeTypeManager nodeTypeMgr; @Override @Before public void beforeEach() throws Exception { super.beforeEach(); nodeTypeMgr = session().nodeTypeManager(); } @Test(expected = IllegalArgumentException.class) public void shouldNotAllowNullSubTypeNames() throws RepositoryException { this.nodeTypeMgr.isDerivedFrom(null, "nt:base", MIXINS); } @Test(expected = IllegalArgumentException.class) public void shouldNotAllowEmptySubTypeNames() throws Exception { this.nodeTypeMgr.isDerivedFrom(new String[0], "nt:base", MIXINS); } @Test(expected = IllegalArgumentException.class) public void shouldNotAllowNullPrimaryType() throws Exception { this.nodeTypeMgr.isDerivedFrom(SUBTYPES, null, MIXINS); } @Test(expected = IllegalArgumentException.class) public void shouldNotAllowEmptyPrimaryType() throws Exception { this.nodeTypeMgr.isDerivedFrom(SUBTYPES, "", MIXINS); } @Test public void shouldBeDerivedFromIfSubtypeMatchesPrimaryType() throws Exception { assertTrue(this.nodeTypeMgr.isDerivedFrom(SUBTYPES, SUBTYPE2, null)); assertTrue(this.nodeTypeMgr.isDerivedFrom(SUBTYPES, SUBTYPE2, MIXINS)); } @Test public void shouldBeDerivedFromIfSubtypeMatchesMixin() throws Exception { assertTrue(this.nodeTypeMgr.isDerivedFrom(new String[] { MIXIN2 }, SUBTYPE1, MIXINS)); } @Test public void shouldBeDerivedFromIfSubtypeIsActualSubType() throws Exception { assertTrue(this.nodeTypeMgr.isDerivedFrom(SUBTYPES, HIERARCHY_NODE_TYPE, MIXINS)); } @Test public void shouldNotBeDerivedFromIfNoMatch() throws Exception { assertFalse(this.nodeTypeMgr.isDerivedFrom(SUBTYPES, NO_MATCH_TYPE, MIXINS)); } @Test public void shouldReturnTrueForHasNodeTypeWithExistingNodeTypeName() throws Exception { assertTrue(nodeTypeMgr.hasNodeType("nt:base")); assertTrue(nodeTypeMgr.hasNodeType(HIERARCHY_NODE_TYPE)); assertTrue(nodeTypeMgr.hasNodeType(MIXIN1)); } @Test public void shouldReturnFalseForHasNodeTypeWithNonexistantNodeTypeName() throws Exception { assertFalse(nodeTypeMgr.hasNodeType("someArgleBargle")); assertFalse(nodeTypeMgr.hasNodeType(HIERARCHY_NODE_TYPE + "x")); } @Test public void shouldVerifyNtFileHasPrimaryItem() throws Exception { NodeType ntFile = nodeTypeMgr.getNodeType(NT_FILE_NODE_TYPE); assertThat(ntFile.getPrimaryItemName(), is("jcr:content")); } @SuppressWarnings("unchecked") @Test @FixFor("MODE-1954") public void shouldRemovePropertyDefinitionViaTemplate() throws Exception { session.getWorkspace().getNamespaceRegistry().registerNamespace("dmsmix", "http://myexample.com/dms"); NodeTypeTemplate fileContent = nodeTypeMgr.createNodeTypeTemplate(); fileContent.setName("dmsmix:filecontent"); nodeTypeMgr.registerNodeType(fileContent, true); NodeType nodeType = nodeTypeMgr.getNodeType("dmsmix:filecontent"); NodeTypeTemplate nodeTypeTemplate = nodeTypeMgr.createNodeTypeTemplate(nodeType); PropertyDefinitionTemplate tp = nodeTypeMgr.createPropertyDefinitionTemplate(); tp.setName("dmsmix:owner"); nodeTypeTemplate.getPropertyDefinitionTemplates().add(tp); nodeTypeMgr.registerNodeType(nodeTypeTemplate, true); nodeType = nodeTypeMgr.getNodeType("dmsmix:filecontent"); nodeTypeTemplate = nodeTypeMgr.createNodeTypeTemplate(nodeType); List<PropertyDefinitionTemplate> pts = nodeTypeTemplate.getPropertyDefinitionTemplates(); Iterator<PropertyDefinitionTemplate> pit = pts.iterator(); while (pit.hasNext()) { PropertyDefinitionTemplate pi = pit.next(); if (pi.getName().equals("dmsmix:owner")) { pit.remove(); } } nodeTypeMgr.registerNodeType(nodeTypeTemplate, true); } @Test @FixFor("MODE-1963") public void shouldAllowReRegistrationOfMixinViaTemplate() throws Exception { session.getWorkspace().getNamespaceRegistry().registerNamespace("dmsmix", "http://myexample.com/dms"); String mixinName = "dmsmix:test"; registerMixin(mixinName); nodeTypeMgr.unregisterNodeType(mixinName); registerMixin(mixinName); } @Test @FixFor("MODE-1965") public void shouldNotAllowRegistrationOfMixinThatInheritsNonMixin() throws Exception { session.getWorkspace().getNamespaceRegistry().registerNamespace("test", "http://myexample.com/test"); String mixinName = "test:mixin"; try { registerMixin(mixinName, "nt:unstructured"); fail("Should not allow registration of mixin that inherits non-mixin"); } catch (RepositoryException e) { // expected } } @Test @FixFor("MODE-1965") public void shouldNotAllowRegistrationOfMixinThatInheritsBothNonMixinAndMixin() throws Exception { session.getWorkspace().getNamespaceRegistry().registerNamespace("test", "http://myexample.com/test"); registerMixin("test:mixinParent"); try { registerMixin("test:mixinChild", "test:mixinParent", "nt:base"); fail("Should not allow registration of mixin that inherits non-mixin"); } catch (RepositoryException e) { // expected } } @Test @FixFor( "MODE-2150" ) @SuppressWarnings("unchecked") public void shouldAllowRegisteringBooleanConstraints() throws Exception { String namespaceName = "admb"; String namespaceUri = "http://www.admb.be/modeshape/admb/1.0"; String nodeTypeName = "test"; session.getWorkspace().getNamespaceRegistry().registerNamespace(namespaceName, namespaceUri); // Start creating a nodeTypeTemplate but also add the property // definition as BOOLEAN and a String constraint like 'true' NodeTypeTemplate nodeTypeTemplate = nodeTypeMgr.createNodeTypeTemplate(); nodeTypeTemplate.setPrimaryItemName("test"); String primaryType = namespaceName.concat(":").concat(nodeTypeName); nodeTypeTemplate.setName(primaryType); PropertyDefinitionTemplate propertyDefinition = nodeTypeMgr.createPropertyDefinitionTemplate(); propertyDefinition.setName("test"); propertyDefinition.setRequiredType(PropertyType.BOOLEAN); propertyDefinition.setMandatory(true); propertyDefinition.setValueConstraints(new String[] { "true" }); nodeTypeTemplate.getPropertyDefinitionTemplates().add(propertyDefinition); nodeTypeMgr.registerNodeType(nodeTypeTemplate, false); Node node = session.getRootNode().addNode("test", primaryType); node.setProperty("test", true); session.save(); try { node.setProperty("test", false); session.save(); fail("Value which violates constraint did not raise exception"); } catch (ConstraintViolationException e) { //expected node.remove(); session.save(); nodeTypeMgr.unregisterNodeType(primaryType); } } @Test @FixFor( "MODE-2149" ) @SuppressWarnings("unchecked") public void shouldValidateConstraintValue() throws Exception { String namespaceName = "admb"; String namespaceUri = "http://www.admb.be/modeshape/admb/1.0"; String nodeTypeName = "test"; session.getWorkspace().getNamespaceRegistry().registerNamespace(namespaceName, namespaceUri); NodeTypeTemplate nodeTypeTemplate = nodeTypeMgr.createNodeTypeTemplate(); nodeTypeTemplate.setPrimaryItemName("test"); String primaryType = namespaceName.concat(":").concat(nodeTypeName); nodeTypeTemplate.setName(primaryType); PropertyDefinitionTemplate propertyDefinition = nodeTypeMgr.createPropertyDefinitionTemplate(); propertyDefinition.setName("test"); propertyDefinition.setRequiredType(PropertyType.LONG); propertyDefinition.setMandatory(true); propertyDefinition.setValueConstraints(new String[] { "test" }); nodeTypeTemplate.getPropertyDefinitionTemplates().add(propertyDefinition); try { nodeTypeMgr.registerNodeType(nodeTypeTemplate, false); fail("Should not allow the registration of a node type with invalid constraint"); } catch (ValueFormatException e) { //expected } } private void registerMixin( String name, String... declaredSuperTypes ) throws RepositoryException { NodeTypeTemplate nodeTypeTemplate = nodeTypeMgr.createNodeTypeTemplate(); nodeTypeTemplate.setMixin(true); nodeTypeTemplate.setName(name); nodeTypeTemplate.setQueryable(true); if (declaredSuperTypes.length > 0) { nodeTypeTemplate.setDeclaredSuperTypeNames(declaredSuperTypes); } nodeTypeMgr.registerNodeType(nodeTypeTemplate, true); } }