/*
* 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.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.nodetype.InvalidNodeTypeDefinitionException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeTypeDefinition;
import javax.jcr.nodetype.NodeTypeTemplate;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.modeshape.common.FixFor;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.NameFactory;
import org.modeshape.jcr.value.NamespaceRegistry;
public class TypeRegistrationTest extends SingleUseAbstractTest {
private static final String TEST_TYPE_NAME = "mode:testNode";
private static final String TEST_TYPE_NAME2 = "mode:testNode2";
private static final String TEST_PROPERTY_NAME = "mode:testProperty";
private static final String TEST_CHILD_NODE_NAME = "mode:testChildNode";
private ExecutionContext context;
private JcrNodeTypeTemplate ntTemplate;
private NamespaceRegistry registry;
private NameFactory nameFactory;
private RepositoryNodeTypeManager repoTypeManager;
@Override
@Before
public void beforeEach() throws Exception {
super.beforeEach();
context = session.context();
ntTemplate = new JcrNodeTypeTemplate(context);
registry = session.namespaces();
nameFactory = session.nameFactory();
repoTypeManager = session.repository().nodeTypeManager();
}
protected NodeTypes nodeTypes() {
return repoTypeManager.getNodeTypes();
}
protected Value[] valuesFrom( String... values ) throws RepositoryException {
Value[] result = new Value[values.length];
int i = 0;
for (String value : values) {
result[i++] = session.getValueFactory().createValue(value);
}
return result;
}
@Ignore
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNodeTypeWithInvalidName() throws Exception {
ntTemplate.setName("nt-name");
}
@Ignore
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowPropertyWithInvalidName() throws Exception {
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(":foo[2]");
System.out.println(prop.getName());
}
@Ignore
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowChildNodeWithInvalidName() throws Exception {
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(":foo[2]");
}
@Ignore
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowChildNodeWithInvalidRequiredPrimaryTypeName() throws Exception {
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setRequiredPrimaryTypeNames(new String[] {"nt-Name"});
}
@Ignore
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowChildNodeWithInvalidDefaultPrimaryTypeName() throws Exception {
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setDefaultPrimaryTypeName("nt-Name");
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNodeTypeWithNoName() throws Exception {
ntTemplate.setName(null);
}
@Test
public void shouldTranslateNameImmediately() throws Exception {
ntTemplate.setName("{" + ModeShapeLexicon.Namespace.URI + "}foo");
assertThat(ntTemplate.getName(), is("mode:foo"));
}
@Test
public void shouldAllowNewDefinitionWithNoChildNodesOrProperties() throws Exception {
Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base"});
JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate);
assertThat(testNodeType.getName(), is(TEST_TYPE_NAME));
JcrNodeType nodeTypeFromRepo = nodeTypes().getNodeType(testTypeName);
assertThat(nodeTypeFromRepo, is(notNullValue()));
assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME));
}
@Test( expected = NodeTypeExistsException.class )
public void shouldNotAllowModificationIfAllowUpdatesIsFalse() throws Exception {
ntTemplate.setName("nt:base");
repoTypeManager.registerNodeType(ntTemplate);
}
@Test( expected = NodeTypeExistsException.class )
public void shouldNotAllowRedefinitionOfNewTypeIfAllowUpdatesIsFalse() throws Exception {
Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base"});
JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate);
assertThat(testNodeType.getName(), is(TEST_TYPE_NAME));
JcrNodeType nodeTypeFromRepo = nodeTypes().getNodeType(testTypeName);
assertThat(nodeTypeFromRepo, is(notNullValue()));
assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME));
testNodeType = repoTypeManager.registerNodeType(ntTemplate);
}
@Test
public void shouldAllowDefinitionWithExistingSupertypes() throws Exception {
Name testTypeName = nameFactory.create(TEST_TYPE_NAME);
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeType testNodeType = repoTypeManager.registerNodeType(ntTemplate);
assertThat(testNodeType.getName(), is(TEST_TYPE_NAME));
JcrNodeType nodeTypeFromRepo = nodeTypes().getNodeType(testTypeName);
assertThat(nodeTypeFromRepo, is(notNullValue()));
assertThat(nodeTypeFromRepo.getName(), is(TEST_TYPE_NAME));
}
@Test
public void shouldAllowDefinitionWithSupertypesFromTypesRegisteredInSameCall() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(context);
ntTemplate2.setName(TEST_TYPE_NAME2);
ntTemplate2.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowDefinitionWithSupertypesFromTypesRegisteredInSameCallInWrongOrder() throws Exception {
// Try to register the supertype AFTER the class that registers it
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(context);
ntTemplate2.setName(TEST_TYPE_NAME2);
ntTemplate2.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate2, ntTemplate}));
}
@Test
public void shouldAllowDefinitionWithAProperty() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setRequiredType(PropertyType.LONG);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowDefinitionWithProperties() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setRequiredType(PropertyType.LONG);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
JcrPropertyDefinitionTemplate prop2 = new JcrPropertyDefinitionTemplate(this.context);
prop2.setRequiredType(PropertyType.STRING);
prop2.setMultiple(true);
ntTemplate.getPropertyDefinitionTemplates().add(prop2);
JcrPropertyDefinitionTemplate prop3 = new JcrPropertyDefinitionTemplate(this.context);
prop3.setName(TEST_PROPERTY_NAME);
prop3.setRequiredType(PropertyType.STRING);
ntTemplate.getPropertyDefinitionTemplates().add(prop3);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowAutocreatedPropertyWithNoDefault() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.LONG);
prop.setAutoCreated(true);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowAutocreatedResidualProperty() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(JcrNodeType.RESIDUAL_ITEM_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
prop.setAutoCreated(true);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowAutocreatedNamedPropertyWithDefault() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.STRING);
prop.setAutoCreated(true);
prop.setDefaultValues(valuesFrom("<default>"));
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowSingleValuedPropertyWithMultipleDefaults() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.STRING);
prop.setAutoCreated(true);
prop.setDefaultValues(valuesFrom("<default>", "too many values"));
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowMandatoryResidualProperty() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(JcrNodeType.RESIDUAL_ITEM_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
prop.setMandatory(true);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowTypeWithChildNode() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setSameNameSiblings(true);
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowTypeWithMultipleChildNodes() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setSameNameSiblings(true);
ntTemplate.getNodeDefinitionTemplates().add(child);
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:unstructured"});
child.setSameNameSiblings(false);
ntTemplate.getNodeDefinitionTemplates().add(child);
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME + "2");
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setSameNameSiblings(true);
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowAutocreatedChildNodeWithNoDefaultPrimaryType() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setAutoCreated(true);
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowMandatoryResidualChildNode() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrNodeType.RESIDUAL_ITEM_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setMandatory(true);
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingProtectedProperty() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(JcrLexicon.PRIMARY_TYPE.getString(registry));
prop.setRequiredType(PropertyType.NAME);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingProtectedChildNode() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"mode:root", "mix:referenceable"});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingMandatoryChildNodeWithOptionalChildNode() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"jcr:versionHistory",});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
ntTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowOverridingPropertyFromCommonAncestor() throws Exception {
/*
* testNode declares prop testProperty
* testNodeB extends testNode
* testNodeC extends testNode
* testNodeD extends testNodeB and testNodeC and overrides testProperty --> LEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
nodeCTemplate.setName(TEST_TYPE_NAME + "C");
nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrNodeTypeTemplate nodeDTemplate = new JcrNodeTypeTemplate(this.context);
nodeDTemplate.setName(TEST_TYPE_NAME + "D");
nodeDTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME + "B", TEST_TYPE_NAME + "C"});
prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.STRING);
nodeDTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate,
nodeDTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingPropertyFromDifferentAncestors() throws Exception {
/*
* testNode
* testNodeB extends testNode and declares prop testProperty
* testNodeC extends testNode and declares prop testProperty
* testNodeD extends testNodeB and testNodeC and overrides testProperty --> ILLEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
nodeBTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
nodeCTemplate.setName(TEST_TYPE_NAME + "C");
nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
nodeCTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeDTemplate = new JcrNodeTypeTemplate(this.context);
nodeDTemplate.setName(TEST_TYPE_NAME + "D");
nodeDTemplate.setDeclaredSuperTypeNames(new String[] {nodeBTemplate.getName(), nodeCTemplate.getName()});
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate,
nodeDTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowOverridingChildNodeFromCommonAncestor() throws Exception {
/*
* testNode declares node testChildNode
* testNodeB extends testNode
* testNodeC extends testNode
* testNodeD extends testNodeB and testNodeC and overrides testChildNode --> LEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
ntTemplate.getNodeDefinitionTemplates().add(child);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
nodeCTemplate.setName(TEST_TYPE_NAME + "C");
nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrNodeTypeTemplate nodeDTemplate = new JcrNodeTypeTemplate(this.context);
nodeDTemplate.setName(TEST_TYPE_NAME + "D");
nodeDTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME + "B", TEST_TYPE_NAME + "C"});
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:unstructured"});
nodeDTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate,
nodeDTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingChildNodeFromDifferentAncestors() throws Exception {
/*
* testNode
* testNodeB extends testNode and declares node testChildNode
* testNodeC extends testNode and declares node testChildNode
* testNodeD extends testNodeB and testNodeC and overrides testChildNode --> ILLEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
nodeBTemplate.getNodeDefinitionTemplates().add(child);
JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
nodeCTemplate.setName(TEST_TYPE_NAME + "C");
nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(JcrLexicon.SYSTEM.getString(registry));
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
nodeCTemplate.getNodeDefinitionTemplates().add(child);
JcrNodeTypeTemplate nodeDTemplate = new JcrNodeTypeTemplate(this.context);
nodeDTemplate.setName(TEST_TYPE_NAME + "D");
nodeDTemplate.setDeclaredSuperTypeNames(new String[] {nodeBTemplate.getName(), nodeCTemplate.getName()});
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate,
nodeDTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowExtendingPropertyIfMultipleChanges() throws Exception {
/*
* testNode declares SV property testProperty
* testNodeB extends testNode with MV property testProperty with incompatible type -> LEGAL
* testNodeC extends testNode, testNodeB -> LEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.DOUBLE);
prop.setMultiple(false);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.BOOLEAN);
prop.setMultiple(true);
nodeBTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
nodeCTemplate.setName(TEST_TYPE_NAME + "C");
nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME, nodeBTemplate.getName()});
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowOverridingPropertyIfTypeNarrows() throws Exception {
/*
* testNode declares SV property testProperty of type UNDEFINED
* testNodeB extends testNode with SV property testProperty of type STRING -> LEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.UNDEFINED);
prop.setMultiple(false);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.STRING);
prop.setMultiple(false);
nodeBTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingPropertyIfTypeDoesNotNarrow() throws Exception {
/*
* testNode declares SV property testProperty of type BOOLEAN
* testNodeB extends testNode with SV property testProperty of type DOUBLE -> ILLEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrPropertyDefinitionTemplate prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.BOOLEAN);
prop.setMultiple(false);
ntTemplate.getPropertyDefinitionTemplates().add(prop);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
prop = new JcrPropertyDefinitionTemplate(this.context);
prop.setName(TEST_PROPERTY_NAME);
prop.setRequiredType(PropertyType.DOUBLE);
prop.setMultiple(false);
nodeBTemplate.getPropertyDefinitionTemplates().add(prop);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test
public void shouldAllowOverridingChildNodeIfRequiredTypesNarrow() throws Exception {
/*
* testNode declares No-SNS childNode testChildNode requiring type nt:hierarchy
* testNodeB extends testNode with No-SNS childNode testChildNode requiring type nt:file -> LEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:hierarchyNode"});
child.setSameNameSiblings(false);
ntTemplate.getNodeDefinitionTemplates().add(child);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:file"});
child.setSameNameSiblings(false);
nodeBTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowOverridingChildNodeIfRequiredTypesDoNotNarrow() throws Exception {
/*
* testNode declares No-SNS childNode testChildNode requiring type nt:hierarchy
* testNodeB extends testNode with No-SNS childNode testChildNode requiring type nt:base -> ILLEGAL
*/
ntTemplate.setName(TEST_TYPE_NAME);
ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base",});
JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:hierarchyNode"});
child.setSameNameSiblings(false);
ntTemplate.getNodeDefinitionTemplates().add(child);
JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
nodeBTemplate.setName(TEST_TYPE_NAME + "B");
nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});
child = new JcrNodeDefinitionTemplate(this.context);
child.setName(TEST_CHILD_NODE_NAME);
child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
child.setSameNameSiblings(false);
nodeBTemplate.getNodeDefinitionTemplates().add(child);
List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate});
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
}
/*
* Unregistration tests
*/
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowUnregisteringNullCollection() throws Exception {
repoTypeManager.unregisterNodeType(null, true);
}
@Test( expected = NoSuchNodeTypeException.class )
public void shouldNotAllowUnregisteringInvalidTypeNames() throws Exception {
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FILE, JcrLexicon.DATA}), true);
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringSupertype() throws Exception {
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.HIERARCHY_NODE,}), true);
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringRequiredPrimaryType() throws Exception {
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FROZEN_NODE,}), true);
}
@Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringDefaultPrimaryType() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(JcrNtLexicon.FILE.getString(this.registry));
ntTemplate.getNodeDefinitionTemplates().add(childNode);
try {
repoTypeManager.registerNodeType(ntTemplate);
} catch (Exception ex) {
fail(ex.getMessage());
}
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FILE,}), true);
}
@Test
public void shouldAllowUnregisteringUnusedType() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(JcrNtLexicon.FILE.getString(this.registry));
ntTemplate.getNodeDefinitionTemplates().add(childNode);
try {
repoTypeManager.registerNodeType(ntTemplate);
} catch (Exception ex) {
fail(ex.getMessage());
}
Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
int nodeTypeCount = nodeTypes().getAllNodeTypes().size();
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {typeNameAsName}), true);
assertThat(nodeTypes().getAllNodeTypes().size(), is(nodeTypeCount - 1));
assertThat(nodeTypes().getNodeType(typeNameAsName), is(nullValue()));
}
@SuppressWarnings( "unchecked" )
@Test
public void shouldAllowUnregisteringUnusedTypesWithMutualDependencies() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
ntTemplate.getNodeDefinitionTemplates().add(childNode);
NodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(this.context);
ntTemplate2.setName(TEST_TYPE_NAME2);
JcrNodeDefinitionTemplate childNode2 = new JcrNodeDefinitionTemplate(this.context);
childNode2.setDefaultPrimaryTypeName(TEST_TYPE_NAME);
ntTemplate2.getNodeDefinitionTemplates().add(childNode2);
try {
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2}));
} catch (Exception ex) {
fail(ex.getMessage());
}
Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
Name type2NameAsName = nameFactory.create(TEST_TYPE_NAME2);
int nodeTypeCount = nodeTypes().getAllNodeTypes().size();
repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {typeNameAsName, type2NameAsName}), true);
assertThat(nodeTypes().getAllNodeTypes().size(), is(nodeTypeCount - 2));
assertThat(nodeTypes().getNodeType(typeNameAsName), is(nullValue()));
assertThat(nodeTypes().getNodeType(type2NameAsName), is(nullValue()));
}
@FixFor( "MODE-826" )
@Test
public void shouldAllowRegisteringNodeTypeWithOnlyResidualChildNodeDefinition() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
// Create the residual child node definition ...
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
childNode.setName("*");
ntTemplate.getNodeDefinitionTemplates().add(childNode);
// And register it ...
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
}
@FixFor( "MODE-826" )
@Test
public void shouldAllowRegisteringNodeTypeWithPrimaryItemNameAndOnlyNonResidualPropertyNodeDefinition() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
// Set the primary item name to be a name that DOES match the property definition ...
ntTemplate.setPrimaryItemName(TEST_PROPERTY_NAME);
// Create the residual property definition ...
JcrPropertyDefinitionTemplate propertyDefn = new JcrPropertyDefinitionTemplate(this.context);
propertyDefn.setRequiredType(PropertyType.STRING);
propertyDefn.setName(TEST_PROPERTY_NAME);
ntTemplate.getPropertyDefinitionTemplates().add(propertyDefn);
// And register it ...
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
}
@FixFor( "MODE-826" )
@Test
public void shouldAllowRegisteringNodeTypeWithPrimaryItemNameAndOnlyResidualPropertyNodeDefinition() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
// Set the primary item name to be a name that doesn't explicitly match a child node definition or a property definition
// but that is covered by the residual property definition ...
ntTemplate.setPrimaryItemName(TEST_PROPERTY_NAME);
// Create the residual child node definition ...
JcrPropertyDefinitionTemplate propertyDefn = new JcrPropertyDefinitionTemplate(this.context);
propertyDefn.setRequiredType(PropertyType.STRING);
propertyDefn.setName("*");
ntTemplate.getPropertyDefinitionTemplates().add(propertyDefn);
// And register it ...
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
}
@FixFor( "MODE-826" )
@Test
public void shouldAllowRegisteringNodeTypeWithPrimaryItemNameAndOnlyNonResidualChildNodeDefinition() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
// Set the primary item name to be a name that DOES match the child node definition ...
ntTemplate.setPrimaryItemName(TEST_CHILD_NODE_NAME);
// Create the residual child node definition ...
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
childNode.setName(TEST_CHILD_NODE_NAME);
ntTemplate.getNodeDefinitionTemplates().add(childNode);
// And register it ...
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
}
@FixFor( "MODE-826" )
@Test
public void shouldAllowRegisteringNodeTypeWithPrimaryItemNameAndOnlyResidualChildNodeDefinition() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
// Set the primary item name to be a name that doesn't explicitly match a child node definition but that is
// covered by the residual child node definition ...
ntTemplate.setPrimaryItemName(TEST_CHILD_NODE_NAME);
// Create the residual child node definition ...
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
childNode.setName("*");
ntTemplate.getNodeDefinitionTemplates().add(childNode);
// And register it ...
repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
}
private void compareTemplatesToNodeTypes( List<NodeTypeDefinition> templates,
List<JcrNodeType> nodeTypes ) {
assertThat(templates.size(), is(nodeTypes.size()));
for (int i = 0; i < nodeTypes.size(); i++) {
JcrNodeTypeTemplate jntt = (JcrNodeTypeTemplate)templates.get(i);
compareTemplateToNodeType(jntt, null);
compareTemplateToNodeType(jntt, nodeTypes.get(i));
}
}
private void compareTemplateToNodeType( JcrNodeTypeTemplate template,
JcrNodeType nodeType ) {
Name nodeTypeName = nameFactory.create(template.getName());
if (nodeType == null) {
nodeType = nodeTypes().getNodeType(nodeTypeName);
assertThat(nodeType.nodeTypeManager(), is(notNullValue()));
}
NodeTypeAssertion.compareTemplateToNodeType(template, nodeType);
}
}