/* * 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.core.nodetype.xml; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.Arrays; import javax.jcr.NamespaceException; import javax.jcr.NamespaceRegistry; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.version.OnParentVersionAction; import junit.framework.AssertionFailedError; import org.apache.jackrabbit.api.JackrabbitNodeTypeManager; import org.apache.jackrabbit.commons.cnd.CndImporter; import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException; import org.apache.jackrabbit.core.value.InternalValueFactory; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.NameFactory; import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.spi.QPropertyDefinition; import org.apache.jackrabbit.spi.QNodeDefinition; import org.apache.jackrabbit.spi.QNodeTypeDefinition; import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; import org.apache.jackrabbit.spi.commons.name.NameConstants; import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver; import org.apache.jackrabbit.spi.commons.value.ValueFactoryQImpl; import org.apache.jackrabbit.test.AbstractJCRTest; /** * Test cases for reading and writing node type definition files. */ public class TestAll extends AbstractJCRTest { /** The dummy test namespace. */ private static final String TEST_NAMESPACE = "http://www.apache.org/jackrabbit/test"; /** Name of the include test node type definition file. */ private static final String TEST_NODETYPES = "org/apache/jackrabbit/core/nodetype/xml/test_nodetypes.xml"; /** Name of the xml nodetype file for import and namespace registration. */ private static final String TEST_NS_XML_NODETYPES = "test_ns_xml_nodetypes.xml"; /** Name of the cnd nodetype file for import and namespace registration. */ private static final String TEST_NS_CND_NODETYPES = "test_ns_cnd_nodetypes.cnd"; /** Name of the xml nodetype file with same node type name definitions. */ private static final String TEST_SAME_NT_NAME_XML_NODETYPES = "test_same_nt_name_xml_nodetypes.xml"; /** Name of the cnd nodetype file with same node type name definitions. */ private static final String TEST_SAME_NT_NAME_CND_NODETYPES = "test_same_nt_name_cnd_nodetypes.cnd"; private static final NameFactory FACTORY = NameFactoryImpl.getInstance(); /** Test node types definitions. */ private QNodeTypeDefinition[] types; /** Registry for the test namespaces. */ private NamespaceRegistry registry; /** * Initializes the node type formatter tests. * * @throws Exception on initialization errors */ protected void setUp() throws Exception { super.setUp(); InputStream xml = getClass().getClassLoader().getResourceAsStream(TEST_NODETYPES); types = NodeTypeReader.read(xml); registry = new SimpleNamespaceRegistry(); registry.registerNamespace("test", TEST_NAMESPACE); } /** * Returns the named node type definition. If the node type does not * exist, an assertion failure is generated. * * @param name node type name * @return node type definition */ private QNodeTypeDefinition getNodeType(String name) { Name qname = FACTORY.create(TEST_NAMESPACE, name); for (int i = 0; i < types.length; i++) { if (qname.equals(types[i].getName())) { return types[i]; } } throw new AssertionFailedError("Node type " + name + " does not exist"); } /** * Returns the named property definition from the named node type * definition. If either of the definitions do not exist, an assertion * failure is generated. * <p> * If the given property name is <code>null</code>, then the residual * property definition (if one exists) is returned. * * @param typeName node type name * @param propertyName property name, or <code>null</code> * @return property definition */ private QPropertyDefinition getPropDef(String typeName, String propertyName) { Name name; if (propertyName != null) { name = FACTORY.create(TEST_NAMESPACE, propertyName); } else { name = NameConstants.ANY_NAME; } QNodeTypeDefinition def = getNodeType(typeName); QPropertyDefinition[] defs = def.getPropertyDefs(); for (int i = 0; i < defs.length; i++) { if (name.equals(defs[i].getName())) { return defs[i]; } } throw new AssertionFailedError( "Property " + propertyName + " does not exist"); } /** * Returns the string value of the identified property default value. * * @param def property definition * @param index default value index * @return default value */ private String getDefaultValue(QPropertyDefinition def, int index) { try { QValue[] values = def.getDefaultValues(); NamespaceResolver nsResolver = new AdditionalNamespaceResolver(registry); NamePathResolver resolver = new DefaultNamePathResolver(nsResolver); ValueFactoryQImpl factory = new ValueFactoryQImpl(InternalValueFactory.getInstance(), resolver); return factory.createValue(values[index]).getString(); } catch (RepositoryException e) { throw new AssertionFailedError(e.getMessage()); } } /** * Returns the named child node definition from the named node type * definition. If either of the definitions do not exist, an assertion * failure is generated. * * @param typeName node type name * @param nodeName child node name * @return child node definition */ private QNodeDefinition getChildNode(String typeName, String nodeName) { Name name = FACTORY.create(TEST_NAMESPACE, nodeName); QNodeTypeDefinition def = getNodeType(typeName); QNodeDefinition[] defs = def.getChildNodeDefs(); for (int i = 0; i < defs.length; i++) { if (name.equals(defs[i].getName())) { return defs[i]; } } throw new AssertionFailedError( "Child node " + nodeName + " does not exist"); } /** * Test for reading a node type definition file. The test file * has already been read during the test setup, so this method * just verifies the number of node types. */ public void testRead() { assertEquals("number of node types", 6, types.length); } /** Test for the empty node type. */ public void testEmptyNodeType() { QNodeTypeDefinition def = getNodeType("emptyNodeType"); assertNotNull("emptyNodeType exists", def); assertEquals("emptyNodeType mixin", false, def.isMixin()); assertEquals("emptyNodeType hasOrderableChildNodes", false, def.hasOrderableChildNodes()); assertEquals("emptyNodeType primaryItemName", null, def.getPrimaryItemName()); assertEquals("emptyNodeType childNodeDefs", 0, def.getChildNodeDefs().length); assertEquals("emptyNodeType propertyDefs", 0, def.getPropertyDefs().length); } /** Test for the <code>mixin</code> node type attribute. */ public void testMixinNodeType() { QNodeTypeDefinition def = getNodeType("mixinNodeType"); assertEquals("mixinNodeType mixin", true, def.isMixin()); } /** Test for the <code>hasOrderableChildNodes</code> node type attribute. */ public void testOrderedNodeType() { QNodeTypeDefinition def = getNodeType("orderedNodeType"); assertEquals("orderedNodeType hasOrderableChildNodes", true, def.hasOrderableChildNodes()); } /** Test for node type item definitions. */ public void testItemNodeType() { QNodeTypeDefinition def = getNodeType("itemNodeType"); assertEquals("itemNodeType primaryItemName", FACTORY.create(TEST_NAMESPACE, "emptyItem"), def.getPrimaryItemName()); assertEquals("itemNodeType propertyDefs", 10, def.getPropertyDefs().length); QPropertyDefinition pdef = getPropDef("itemNodeType", null); assertTrue("itemNodeType wildcard property", pdef.definesResidual()); } /** Test for namespace registration on node type import. */ public void testImportXMLNodeTypes() throws Exception { try { superuser.getNamespacePrefix("http://ns.example.org/test-namespace2"); // Ignore test case, node type and namespace already registered } catch (NamespaceException e1) { // Namespace testns2 not yet registered JackrabbitNodeTypeManager ntm = (JackrabbitNodeTypeManager) superuser.getWorkspace().getNodeTypeManager(); ntm.registerNodeTypes( TestAll.class.getResourceAsStream(TEST_NS_XML_NODETYPES), JackrabbitNodeTypeManager.TEXT_XML); try { superuser.getNamespacePrefix("http://ns.example.org/test-namespace2"); } catch (NamespaceException e2) { fail("xml test2 namespace not registered"); } } } /** Test for same node type name on node type import. */ public void testInvalidXMLNodeTypes() throws Exception { JackrabbitNodeTypeManager ntm = (JackrabbitNodeTypeManager) superuser.getWorkspace().getNodeTypeManager(); try { ntm.registerNodeTypes( TestAll.class.getResourceAsStream(TEST_SAME_NT_NAME_XML_NODETYPES), JackrabbitNodeTypeManager.TEXT_XML); fail("Importing multiple node types with the same name must fail"); } catch (RepositoryException e) { if (e.getCause() instanceof InvalidNodeTypeDefException) { // Expected } else { throw e; } } } /** Test for namespace registration on node type import. */ public void testImportCNDNodeTypes() throws Exception { try { superuser.getNamespacePrefix("http://ns.example.org/test-namespace3"); // Ignore test case, node type and namespace already registered } catch (NamespaceException e1) { Reader cnd = new InputStreamReader(TestAll.class.getResourceAsStream(TEST_NS_CND_NODETYPES)); CndImporter.registerNodeTypes(cnd, superuser); cnd.close(); try { superuser.getNamespacePrefix("http://ns.example.org/test-namespace3"); } catch (NamespaceException e2) { fail("cnd test3 namespace not registered"); } } } /** Test for same node type name on node type import. */ public void testInvalidCNDNodeTypes() throws Exception { JackrabbitNodeTypeManager ntm = (JackrabbitNodeTypeManager) superuser.getWorkspace().getNodeTypeManager(); try { ntm.registerNodeTypes( TestAll.class.getResourceAsStream(TEST_SAME_NT_NAME_CND_NODETYPES), JackrabbitNodeTypeManager.TEXT_X_JCR_CND); fail("Importing multiple node types with the same name must fail"); } catch (RepositoryException e) { if (e.getCause() instanceof InvalidNodeTypeDefException) { // Expected } else { throw e; } } } /** Test for the empty item definition. */ public void testEmptyItem() { QPropertyDefinition def = getPropDef("itemNodeType", "emptyItem"); assertEquals("emptyItem autoCreate", false, def.isAutoCreated()); assertEquals("emptyItem mandatory", false, def.isMandatory()); assertEquals("emptyItem onParentVersion", OnParentVersionAction.IGNORE, def.getOnParentVersion()); assertEquals("emptyItem protected", false, def.isProtected()); } /** Test for the <code>autoCreated</code> item definition attribute. */ public void testAutoCreateItem() { QPropertyDefinition def = getPropDef("itemNodeType", "autoCreatedItem"); assertEquals("autoCreatedItem autoCreated", true, def.isAutoCreated()); } /** Test for the <code>mandatory</code> item definition attribute. */ public void testMandatoryItem() { QPropertyDefinition def = getPropDef("itemNodeType", "mandatoryItem"); assertEquals("mandatoryItem mandatory", true, def.isMandatory()); } /** Test for the <code>copy</code> parent version action. */ public void testCopyItem() { QPropertyDefinition def = getPropDef("itemNodeType", "copyItem"); assertEquals("copyItem onParentVersion", OnParentVersionAction.COPY, def.getOnParentVersion()); } /** Test for the <code>version</code> parent version action. */ public void testVersionItem() { QPropertyDefinition def = getPropDef("itemNodeType", "versionItem"); assertEquals("versionItem onParentVersion", OnParentVersionAction.VERSION, def.getOnParentVersion()); } /** Test for the <code>initialize</code> parent version action. */ public void testInitializeItem() { QPropertyDefinition def = getPropDef("itemNodeType", "initializeItem"); assertEquals("initializeItem onParentVersion", OnParentVersionAction.INITIALIZE, def.getOnParentVersion()); } /** Test for the <code>compute</code> parent version action. */ public void testComputeItem() { QPropertyDefinition def = getPropDef("itemNodeType", "computeItem"); assertEquals("computeItem onParentVersion", OnParentVersionAction.COMPUTE, def.getOnParentVersion()); } /** Test for the <code>abort</code> parent version action. */ public void testAbortItem() { QPropertyDefinition def = getPropDef("itemNodeType", "abortItem"); assertEquals("abortItem onParentVersion", OnParentVersionAction.ABORT, def.getOnParentVersion()); } /** Test for the <code>protected</code> item definition attribute. */ public void testProtectedItem() { QPropertyDefinition def = getPropDef("itemNodeType", "protectedItem"); assertEquals("protectedItem protected", true, def.isProtected()); } /** Test for node type property definitions. */ public void testPropertyNodeType() { QNodeTypeDefinition def = getNodeType("propertyNodeType"); assertEquals("propertyNodeType propertyDefs", 13, def.getPropertyDefs().length); } /** Test for the empty property definition. */ public void testEmptyProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "emptyProperty"); assertEquals("emptyProperty requiredType", PropertyType.UNDEFINED, def.getRequiredType()); assertEquals("emptyProperty multiple", false, def.isMultiple()); assertNull("emptyProperty defaultValues", def.getDefaultValues()); assertEquals("emptyProperty valueConstraints", 0, def.getValueConstraints().length); } /** Test for the <code>binary</code> property definition type. */ public void testBinaryProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "binaryProperty"); assertEquals("binaryProperty requiredType", PropertyType.BINARY, def.getRequiredType()); assertEquals("binaryProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("binaryProperty valueConstraints[0]", "[0,)", (def.getValueConstraints())[0].getString()); assertNull("binaryProperty defaultValues", def.getDefaultValues()); } /** Test for the <code>boolean</code> property definition type. */ public void testBooleanProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "booleanProperty"); assertEquals("booleanProperty requiredType", PropertyType.BOOLEAN, def.getRequiredType()); assertEquals("booleanProperty valueConstraints", 2, def.getValueConstraints().length); assertEquals("booleanProperty valueConstraints[0]", "true", (def.getValueConstraints())[0].getString()); assertEquals("booleanProperty valueConstraints[1]", "false", (def.getValueConstraints())[1].getString()); assertEquals("booleanProperty defaultValues", 1, def.getDefaultValues().length); assertEquals("booleanProperty defaultValues[0]", "true", getDefaultValue(def, 0)); } /** Test for the <code>date</code> property definition type. */ public void testDateProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "dateProperty"); assertEquals("dateProperty requiredType", PropertyType.DATE, def.getRequiredType()); assertEquals("dateProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("dateProperty valueConstraints[0]", "[2005-01-01T00:00:00.000Z,2006-01-01T00:00:00.000Z)", (def.getValueConstraints())[0].getString()); assertEquals("dateProperty defaultValues", 1, def.getDefaultValues().length); assertEquals("dateProperty defaultValues[0]", "2005-01-01T00:00:00.000Z", getDefaultValue(def, 0)); } /** Test for the <code>double</code> property definition type. */ public void testDoubleProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "doubleProperty"); assertEquals("doubleProperty requiredType", PropertyType.DOUBLE, def.getRequiredType()); assertEquals("doubleProperty valueConstraints", 3, def.getValueConstraints().length); assertEquals("doubleProperty valueConstraints[0]", "[,0.0)", (def.getValueConstraints())[0].getString()); assertEquals("doubleProperty valueConstraints[1]", "(1.0,2.0)", (def.getValueConstraints())[1].getString()); assertEquals("doubleProperty valueConstraints[2]", "(3.0,]", (def.getValueConstraints())[2].getString()); assertEquals("doubleProperty defaultValues", 1, def.getDefaultValues().length); assertEquals("doubleProperty defaultValues[0]", "1.5", getDefaultValue(def, 0)); } /** Test for the <code>long</code> property definition type. */ public void testLongProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "longProperty"); assertEquals("longProperty requiredType", PropertyType.LONG, def.getRequiredType()); assertEquals("longProperty valueConstraints", 3, def.getValueConstraints().length); assertEquals("longProperty valueConstraints[0]", "(-10,0]", (def.getValueConstraints())[0].getString()); assertEquals("longProperty valueConstraints[1]", "[1,2]", (def.getValueConstraints())[1].getString()); assertEquals("longProperty valueConstraints[2]", "[10,100)", (def.getValueConstraints())[2].getString()); assertEquals("longProperty defaultValues", 1, def.getDefaultValues().length); assertEquals("longProperty defaultValues[0]", "25", getDefaultValue(def, 0)); } /** Test for the <code>name</code> property definition type. */ public void testNameProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "nameProperty"); assertEquals("nameProperty requiredType", PropertyType.NAME, def.getRequiredType()); assertEquals("nameProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("nameProperty valueConstraints[0]", "{http://www.apache.org/jackrabbit/test}testName", (def.getValueConstraints())[0].getString()); assertEquals("nameProperty defaultValues", 1, def.getDefaultValues().length); assertEquals("nameProperty defaultValues[0]", "test:testName", getDefaultValue(def, 0)); } /** Test for the <code>path</code> property definition type. */ public void testPathProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "pathProperty"); assertEquals("pathProperty requiredType", PropertyType.PATH, def.getRequiredType()); assertEquals("pathProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("pathProperty valueConstraints[0]", "{}\t{http://www.apache.org/jackrabbit/test}testPath", (def.getValueConstraints())[0].getString()); assertNull("pathProperty defaultValues", def.getDefaultValues()); } /** Test for the <code>path</code> property definition type. */ public void testPathProperty1() { QPropertyDefinition def = getPropDef("propertyNodeType", "pathProperty1"); assertEquals("pathProperty requiredType", PropertyType.PATH, def.getRequiredType()); assertEquals("pathProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("pathProperty valueConstraints[0]", "{}\t{http://www.apache.org/jackrabbit/test}testPath\t{}*", (def.getValueConstraints())[0].getString()); assertNull("pathProperty defaultValues", def.getDefaultValues()); } /** Test for the <code>path</code> property definition type. */ public void testPathProperty2() { QPropertyDefinition def = getPropDef("propertyNodeType", "pathProperty2"); assertEquals("pathProperty requiredType", PropertyType.PATH, def.getRequiredType()); assertEquals("pathProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("pathProperty valueConstraints[0]", "{http://www.apache.org/jackrabbit/test}testPath\t{}*", (def.getValueConstraints())[0].getString()); assertNull("pathProperty defaultValues", def.getDefaultValues()); } /** Test for the <code>reference</code> property definition type. */ public void testReferenceProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "referenceProperty"); assertEquals("referenceProperty requiredType", PropertyType.REFERENCE, def.getRequiredType()); assertEquals("referenceProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("referenceProperty valueConstraints[0]", "{http://www.jcp.org/jcr/nt/1.0}base", (def.getValueConstraints())[0].getString()); assertNull("referenceProperty defaultValues", def.getDefaultValues()); } /** Test for the <code>string</code> property definition type. */ public void testStringProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "stringProperty"); assertEquals("stringProperty requiredType", PropertyType.STRING, def.getRequiredType()); assertEquals("stringProperty valueConstraints", 1, def.getValueConstraints().length); assertEquals("stringProperty valueConstraints[0]", "bananas?", (def.getValueConstraints())[0].getString()); assertEquals("stringProperty defaultValues", 2, def.getDefaultValues().length); assertEquals("stringProperty defaultValues[0]", "banana", getDefaultValue(def, 0)); assertEquals("stringProperty defaultValues[1]", "bananas", getDefaultValue(def, 1)); } /** Test for the <code>multiple</code> property definition attribute. */ public void testMultipleProperty() { QPropertyDefinition def = getPropDef("propertyNodeType", "multipleProperty"); assertEquals("multipleProperty multiple", true, def.isMultiple()); } /** Test for node type child node definitions. */ public void testChildNodeType() { QNodeTypeDefinition def = getNodeType("childNodeType"); assertEquals("childNodeType childNodeDefs", 4, def.getChildNodeDefs().length); } /** Test for the empty child node definition. */ public void testEmptyNode() { QNodeDefinition def = getChildNode("childNodeType", "emptyNode"); assertEquals("emptyNode allowsSameNameSiblings", false, def.allowsSameNameSiblings()); assertEquals("emptyNode defaultPrimaryType", null, def.getDefaultPrimaryType()); } /** Test for the <code>allowsSameNameSiblings</code> child node attribute. */ public void testSiblingNode() { QNodeDefinition def = getChildNode("childNodeType", "siblingNode"); assertEquals("siblingNode allowsSameNameSiblings", true, def.allowsSameNameSiblings()); } /** Test for the <code>defaultPrimaryType</code> child node attribute. */ public void testDefaultTypeNode() { QNodeDefinition def = getChildNode("childNodeType", "defaultTypeNode"); assertEquals("defaultTypeNode defaultPrimaryType", FACTORY.create(Name.NS_NT_URI, "base"), def.getDefaultPrimaryType()); } /** Test for the <code>requiredPrimaryTypes</code> child node attributes. */ public void testRequiredTypeNode() { QNodeDefinition def = getChildNode("childNodeType", "requiredTypeNode"); assertEquals("requiredTypeNode requiredPrimaryTypes", 2, def.getRequiredPrimaryTypes().length); Name[] types = def.getRequiredPrimaryTypes(); Arrays.sort(types); assertEquals("requiredTypeNode requiredPrimaryTypes[0]", FACTORY.create(Name.NS_NT_URI, "base"), types[0]); assertEquals("requiredTypeNode requiredPrimaryTypes[1]", FACTORY.create(Name.NS_NT_URI, "unstructured"), types[1]); } /** * Test for writing a node type definition file. Writing is tested * by writing and re-reading the test node types using an internal * byte array. The resulting node type map is then compared to the * original test node types. * * @throws IOException on IO errors * @throws RepositoryException on repository errors */ public void testWrite() throws IOException, RepositoryException { try { ByteArrayOutputStream xml = new ByteArrayOutputStream(); NodeTypeWriter.write(xml, types, registry); byte[] bytes = xml.toByteArray(); QNodeTypeDefinition[] output = NodeTypeReader.read(new ByteArrayInputStream(bytes)); assertTrue("write output", Arrays.equals(types, output)); } catch (InvalidNodeTypeDefException e) { fail(e.getMessage()); } } }