/* * 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.assertEquals; import static org.junit.Assert.assertThat; import java.util.Collections; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeTypeDefinition; import javax.jcr.nodetype.NodeTypeTemplate; import org.junit.Before; import org.junit.Test; import org.modeshape.jcr.api.Namespaced; import org.modeshape.jcr.value.Name; import org.modeshape.jcr.value.NameFactory; import org.modeshape.jcr.value.basic.BasicName; public class ItemDefinitionTest extends SingleUseAbstractTest { private static final Name NODE_TYPE_A = new BasicName(TestLexicon.Namespace.URI, "nodeA"); private static final Name NODE_TYPE_B = new BasicName(TestLexicon.Namespace.URI, "nodeB"); private static final Name NODE_TYPE_C = new BasicName(TestLexicon.Namespace.URI, "nodeC"); private static final Name SINGLE_PROP1 = new BasicName(TestLexicon.Namespace.URI, "singleProp1"); private static final Name SINGLE_PROP2 = new BasicName(TestLexicon.Namespace.URI, "singleProp2"); protected NameFactory nameFactory; protected RepositoryNodeTypeManager repoTypeManager; @Override @Before public void beforeEach() throws Exception { super.beforeEach(); nameFactory = session.nameFactory(); repoTypeManager = session.repository().nodeTypeManager(); session.getWorkspace().getNodeTypeManager().registerNodeTypes(getTestTypes(), true); } protected NodeTypes nodeTypes() { return repoTypeManager.getNodeTypes(); } @Test public void shouldNotFindInvalidPropertyDefinition() throws Exception { // This property name is not defined for any of our test types Name badName = nameFactory.create("undefinedName"); JcrPropertyDefinition propDef; propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_A, Collections.<Name>emptyList(), badName, null, true, true, true); assertThat(propDef, is(nullValue())); propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_B, Collections.<Name>emptyList(), badName, null, true, true, true); assertThat(propDef, is(nullValue())); propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_C, Collections.<Name>emptyList(), badName, null, true, true, true); assertThat(propDef, is(nullValue())); } @Test public void shouldUseNearestPropertyDefinition() { // If a property is defined at multiple points in the type hierarchy, the property definition closest to the given type // should be used. JcrPropertyDefinition propDef; propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_A, Collections.<Name>emptyList(), SINGLE_PROP1, null, true, true, true); assertThat(propDef, is(notNullValue())); assertEquals(propDef.getRequiredType(), PropertyType.STRING); propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_B, Collections.<Name>emptyList(), SINGLE_PROP1, null, true, true, true); assertThat(propDef, is(notNullValue())); assertEquals(propDef.getRequiredType(), PropertyType.DOUBLE); propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_C, Collections.<Name>emptyList(), SINGLE_PROP1, null, true, true, true); assertThat(propDef, is(notNullValue())); assertEquals(propDef.getRequiredType(), PropertyType.LONG); } @Test public void shouldFindBestMatchDefinition() throws RepositoryException { /* * In cases where there is more than one valid definition for the same property, * the best match should be returned. */ Value doubleValue = session.getValueFactory().createValue(0.7); Value longValue = session.getValueFactory().createValue(10); Value stringValue = session.getValueFactory().createValue("Should not work"); JcrPropertyDefinition propDef; // Should prefer the double definition from NODE_TYPE_C since the value is of type double propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_C, Collections.<Name>emptyList(), SINGLE_PROP2, doubleValue, true, true); assertThat(propDef, is(notNullValue())); assertEquals(propDef.getRequiredType(), PropertyType.DOUBLE); // Should prefer the long definition from NODE_TYPE_C since the value is of type long propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_C, Collections.<Name>emptyList(), SINGLE_PROP2, longValue, true, true); assertThat(propDef, is(notNullValue())); assertEquals(propDef.getRequiredType(), PropertyType.LONG); // Should not allow a string though, since the NODE_TYPE_C definition narrows the acceptable types to double and long propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_C, Collections.<Name>emptyList(), SINGLE_PROP2, stringValue, true, true); assertThat(propDef, is(nullValue())); } @Test public void shouldBeNamespaced() throws RepositoryException { JcrPropertyDefinition propDef; propDef = nodeTypes().findPropertyDefinition(session, NODE_TYPE_A, Collections.<Name>emptyList(), SINGLE_PROP1, null, true, true, true); assertLocalNameAndNamespace(propDef, SINGLE_PROP1.getLocalName(), TestLexicon.Namespace.PREFIX); } /* * Build a hierarchy of node types with the following relationships: * * modetest:nodeA extends nt:base * modetest:nodeB extends nt:base * modetest:nodeC extends modetest:nodeB * * And the following single-valued property definitions * * modetest:nodeA defines properties: * modetest:singleProp1 of type STRING * modetest:nodeB defines properties: * modetest:singleProp1 of type DOUBLE * modetest:singleProp2 of type UNDEFINED * modetest:nodeC defines properties: * modetest:singleProp1 of type LONG * modetest:singleProp2 of type DOUBLE * modetest:singleProp2 of type LONG (note the double-definition) */ @SuppressWarnings( "unchecked" ) protected NodeTypeDefinition[] getTestTypes() throws ConstraintViolationException, RepositoryException { ExecutionContext context = session.context(); session.getWorkspace().getNamespaceRegistry().registerNamespace("modetest", "http://www.modeshape.org/test/1.0"); NodeTypeTemplate nodeA = new JcrNodeTypeTemplate(context); nodeA.setName("modetest:nodeA"); JcrPropertyDefinitionTemplate nodeASingleProp1 = new JcrPropertyDefinitionTemplate(context); nodeASingleProp1.setName("modetest:singleProp1"); nodeASingleProp1.setRequiredType(PropertyType.STRING); nodeA.getPropertyDefinitionTemplates().add(nodeASingleProp1); NodeTypeTemplate nodeB = new JcrNodeTypeTemplate(context); nodeB.setName("modetest:nodeB"); JcrPropertyDefinitionTemplate nodeBSingleProp1 = new JcrPropertyDefinitionTemplate(context); nodeBSingleProp1.setName("modetest:singleProp1"); nodeBSingleProp1.setRequiredType(PropertyType.DOUBLE); nodeB.getPropertyDefinitionTemplates().add(nodeBSingleProp1); JcrPropertyDefinitionTemplate nodeBSingleProp2 = new JcrPropertyDefinitionTemplate(context); nodeBSingleProp2.setName("modetest:singleProp2"); nodeBSingleProp2.setRequiredType(PropertyType.UNDEFINED); nodeB.getPropertyDefinitionTemplates().add(nodeBSingleProp2); NodeTypeTemplate nodeC = new JcrNodeTypeTemplate(context); nodeC.setName("modetest:nodeC"); nodeC.setDeclaredSuperTypeNames(new String[] {"modetest:nodeB"}); JcrPropertyDefinitionTemplate nodeCSingleProp1 = new JcrPropertyDefinitionTemplate(context); nodeCSingleProp1.setName("modetest:singleProp1"); nodeCSingleProp1.setRequiredType(PropertyType.LONG); nodeC.getPropertyDefinitionTemplates().add(nodeCSingleProp1); JcrPropertyDefinitionTemplate nodeCSingleProp2Double = new JcrPropertyDefinitionTemplate(context); nodeCSingleProp2Double.setName("modetest:singleProp2"); nodeCSingleProp2Double.setRequiredType(PropertyType.DOUBLE); nodeC.getPropertyDefinitionTemplates().add(nodeCSingleProp2Double); JcrPropertyDefinitionTemplate nodeCSingleProp2Long = new JcrPropertyDefinitionTemplate(context); nodeCSingleProp2Long.setName("modetest:singleProp2"); nodeCSingleProp2Long.setRequiredType(PropertyType.LONG); nodeC.getPropertyDefinitionTemplates().add(nodeCSingleProp2Long); return new NodeTypeDefinition[] {nodeA, nodeB, nodeC}; } private void assertLocalNameAndNamespace( Namespaced nsed, String expectedLocalName, String namespacePrefix ) throws RepositoryException { assertThat(nsed.getLocalName(), is(expectedLocalName)); assertThat(nsed.getNamespaceURI(), is(session.getNamespaceURI(namespacePrefix))); } }