Author: jukka
Date: Mon Jan 20 19:45:09 2014
New Revision: 1559816
URL: http://svn.apache.org/r1559816
Log:
OAK-411: Validator for node type management
Avoid full content scan for node type updates that make no actual changes.
Also add more detailed toString() methods to the type templates.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ItemDefinitionTemplate.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeDefinitionTemplateImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeTypeTemplateImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/PropertyDefinitionTemplateImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ReadWriteNodeTypeManager.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/nodetype/NodeTypeTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeImpl.java
Mon Jan 20 19:45:09 2014
@@ -26,8 +26,11 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
@@ -59,6 +62,7 @@ import com.google.common.collect.Sets;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newTreeMap;
import static java.util.Collections.emptyList;
import static org.apache.jackrabbit.JcrConstants.JCR_CHILDNODEDEFINITION;
import static org.apache.jackrabbit.JcrConstants.JCR_HASORDERABLECHILDNODES;
@@ -100,6 +104,16 @@ class NodeTypeImpl extends AbstractTypeD
private static final Logger log =
LoggerFactory.getLogger(NodeTypeImpl.class);
+ /**
+ * Name pattern for the property and child node definition nodes.
+ * Used to pick out the SNS indices from the names so the definitions
+ * can be sorted in the same order they were created. This in turn
+ * makes accessing node type information more deterministic.
+ */
+ private final Pattern DEFINITION_PATTERN = Pattern.compile(
+ "(" + JCR_PROPERTYDEFINITION + "|" + JCR_CHILDNODEDEFINITION
+ + ")\\[([1-9][0-9]*)\\]");
+
private static final PropertyDefinition[] NO_PROPERTY_DEFINITIONS =
new PropertyDefinition[0];
@@ -177,26 +191,44 @@ class NodeTypeImpl extends AbstractTypeD
}
}
- @Override
+ /**
+ * Returns the declared property definitions in their original order.
+ *
+ * @return declared property definitions
+ */
+ @Override @Nonnull
public PropertyDefinition[] getDeclaredPropertyDefinitions() {
- List<PropertyDefinition> definitions = Lists.newArrayList();
+ Map<Integer, PropertyDefinition> definitions = newTreeMap();
for (Tree child : definition.getChildren()) {
- if (child.getName().startsWith(JCR_PROPERTYDEFINITION)) {
- definitions.add(new PropertyDefinitionImpl(child, this,
mapper));
+ Matcher matcher = DEFINITION_PATTERN.matcher(child.getName());
+ if (matcher.matches()
+ && JCR_PROPERTYDEFINITION.equals(matcher.group(1))) {
+ definitions.put(
+ Integer.valueOf(matcher.group(2)),
+ new PropertyDefinitionImpl(child, this, mapper));
}
}
- return definitions.toArray(NO_PROPERTY_DEFINITIONS);
+ return definitions.values().toArray(NO_PROPERTY_DEFINITIONS);
}
- @Override
+ /**
+ * Returns the declared child node definitions in their original order.
+ *
+ * @return declared child node definitions
+ */
+ @Override @Nonnull
public NodeDefinition[] getDeclaredChildNodeDefinitions() {
- List<NodeDefinition> definitions = Lists.newArrayList();
+ Map<Integer, NodeDefinition> definitions = newTreeMap();
for (Tree child : definition.getChildren()) {
- if (child.getName().startsWith(JCR_CHILDNODEDEFINITION)) {
- definitions.add(new NodeDefinitionImpl(child, this, mapper));
+ Matcher matcher = DEFINITION_PATTERN.matcher(child.getName());
+ if (matcher.matches()
+ && JCR_CHILDNODEDEFINITION.equals(matcher.group(1))) {
+ definitions.put(
+ Integer.valueOf(matcher.group(2)),
+ new NodeDefinitionImpl(child, this, mapper));
}
}
- return definitions.toArray(NO_NODE_DEFINITIONS);
+ return definitions.values().toArray(NO_NODE_DEFINITIONS);
}
@Override
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ItemDefinitionTemplate.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ItemDefinitionTemplate.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ItemDefinitionTemplate.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ItemDefinitionTemplate.java
Mon Jan 20 19:45:09 2014
@@ -49,9 +49,9 @@ abstract class ItemDefinitionTemplate ex
private int onParentVersion = OnParentVersionAction.COPY;
- protected boolean isProtected = false;
+ private boolean isProtected = false;
- protected boolean isMandatory = false;
+ private boolean isMandatory = false;
protected ItemDefinitionTemplate(NameMapper mapper) {
super(mapper);
@@ -82,6 +82,8 @@ abstract class ItemDefinitionTemplate ex
throw new RepositoryException("Unnamed item definition");
}
tree.setProperty(JCR_NAME, oakName, Type.NAME);
+ } else {
+ tree.removeProperty(JCR_NAME);
}
// TODO avoid (in validator?) unbounded recursive auto creation.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeDefinitionTemplateImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeDefinitionTemplateImpl.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeDefinitionTemplateImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeDefinitionTemplateImpl.java
Mon Jan 20 19:45:09 2014
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
import static org.apache.jackrabbit.JcrConstants.JCR_DEFAULTPRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.JCR_REQUIREDPRIMARYTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_SAMENAMESIBLINGS;
+import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.RESIDUAL_NAME;
import java.util.Arrays;
@@ -27,11 +28,14 @@ import javax.jcr.nodetype.ConstraintViol
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeDefinitionTemplate;
import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.OnParentVersionAction;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.namepath.NameMapper;
+import com.google.common.base.Objects;
+
class NodeDefinitionTemplateImpl extends ItemDefinitionTemplate
implements NodeDefinitionTemplate {
@@ -71,12 +75,16 @@ class NodeDefinitionTemplateImpl extends
tree.setProperty(
JCR_REQUIREDPRIMARYTYPES,
Arrays.asList(requiredPrimaryTypeOakNames), Type.NAMES);
+ } else {
+ tree.removeProperty(JCR_REQUIREDPRIMARYTYPES);
}
if (defaultPrimaryTypeOakName != null) {
tree.setProperty(
JCR_DEFAULTPRIMARYTYPE,
defaultPrimaryTypeOakName, Type.NAME);
+ } else {
+ tree.removeProperty(JCR_DEFAULTPRIMARYTYPE);
}
}
@@ -140,8 +148,33 @@ class NodeDefinitionTemplateImpl extends
//------------------------------------------------------------< Object >--
+ @Override
public String toString() {
- return String.format("PropertyDefinitionTemplate(%s)", getOakName());
+ StringBuilder builder = new StringBuilder("+ ");
+ if (getOakName() == null) {
+ builder.append(RESIDUAL_NAME);
+ } else {
+ builder.append(getOakName());
+ }
+ if (defaultPrimaryTypeOakName != null) {
+ builder.append(" (");
+ builder.append(defaultPrimaryTypeOakName);
+ builder.append(")");
+ }
+ if (isAutoCreated()) {
+ builder.append(" a");
+ }
+ if (isProtected()) {
+ builder.append(" p");
+ }
+ if (isMandatory()) {
+ builder.append(" m");
+ }
+ if (getOnParentVersion() != OnParentVersionAction.COPY) {
+ builder.append(" ");
+
builder.append(OnParentVersionAction.nameFromValue(getOnParentVersion()));
+ }
+ return builder.toString();
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeTypeTemplateImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeTypeTemplateImpl.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeTypeTemplateImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/NodeTypeTemplateImpl.java
Mon Jan 20 19:45:09 2014
@@ -27,6 +27,7 @@ import static org.apache.jackrabbit.JcrC
import static org.apache.jackrabbit.JcrConstants.NT_CHILDNODEDEFINITION;
import static org.apache.jackrabbit.JcrConstants.NT_NODETYPE;
import static org.apache.jackrabbit.JcrConstants.NT_PROPERTYDEFINITION;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_ABSTRACT;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_QUERYABLE;
@@ -45,6 +46,7 @@ import javax.jcr.nodetype.PropertyDefini
import javax.jcr.nodetype.PropertyDefinitionTemplate;
import com.google.common.collect.Lists;
+
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.namepath.NameMapper;
@@ -129,23 +131,22 @@ class NodeTypeTemplateImpl extends Named
String oakName = getOakName();
Tree type = parent.getChild(oakName);
- if (type.exists()) {
- if (allowUpdate) {
- type.remove();
- } else {
- throw new NodeTypeExistsException(
- "Node type " + getName() + " already exists");
- }
+ if (!type.exists()) {
+ type = parent.addChild(oakName);
+ type.setProperty(JCR_PRIMARYTYPE, NT_NODETYPE, Type.NAME);
+ } else if (!allowUpdate) {
+ throw new NodeTypeExistsException(
+ "Node type " + getName() + " already exists");
}
- type = parent.addChild(oakName);
- type.setProperty(JCR_PRIMARYTYPE, NT_NODETYPE, Type.NAME);
type.setProperty(JCR_NODETYPENAME, oakName, Type.NAME);
if (superTypeOakNames.length > 0) {
type.setProperty(
JCR_SUPERTYPES,
Arrays.asList(superTypeOakNames), Type.NAMES);
+ } else {
+ type.removeProperty(JCR_SUPERTYPES);
}
type.setProperty(JCR_IS_ABSTRACT, isAbstract);
@@ -160,29 +161,50 @@ class NodeTypeTemplateImpl extends Named
// See 3.7.6.7 Node Type Attribute Subtyping Rules (OAK-411)
if (primaryItemOakName != null) {
type.setProperty(JCR_PRIMARYITEMNAME, primaryItemOakName,
Type.NAME);
+ } else {
+ type.removeProperty(JCR_PRIMARYITEMNAME);
}
+ Tree tree;
// TODO fail (in validator?) on invalid item definitions
// See 3.7.6.8 Item Definitions in Subtypes (OAK-411)
+ int pdn = 1;
if (propertyDefinitionTemplates != null) {
- int pdn = 1;
for (PropertyDefinitionTemplateImpl pdt :
propertyDefinitionTemplates) {
- Tree tree = type.addChild(JCR_PROPERTYDEFINITION + "[" + pdn++
+ "]");
- tree.setProperty(
- JCR_PRIMARYTYPE, NT_PROPERTYDEFINITION, Type.NAME);
+ String name = JCR_PROPERTYDEFINITION + "[" + pdn++ + "]";
+ tree = type.getChild(name);
+ if (!tree.exists()) {
+ tree = type.addChild(name);
+ tree.setProperty(
+ JCR_PRIMARYTYPE, NT_PROPERTYDEFINITION, NAME);
+ }
pdt.writeTo(tree);
}
}
+ tree = type.getChild(JCR_PROPERTYDEFINITION + "[" + pdn++ + "]");
+ while (tree.exists()) {
+ tree.remove();
+ tree = type.getChild(JCR_PROPERTYDEFINITION + "[" + pdn++ + "]");
+ }
+ int ndn = 1;
if (nodeDefinitionTemplates != null) {
- int ndn = 1;
for (NodeDefinitionTemplateImpl ndt : nodeDefinitionTemplates) {
- Tree tree = type.addChild(JCR_CHILDNODEDEFINITION + "[" +
ndn++ + "]");
- tree.setProperty(
- JCR_PRIMARYTYPE, NT_CHILDNODEDEFINITION, Type.NAME);
+ String name = JCR_CHILDNODEDEFINITION + "[" + ndn++ + "]";
+ tree = type.getChild(name);
+ if (!tree.exists()) {
+ tree = type.addChild(name);
+ tree.setProperty(
+ JCR_PRIMARYTYPE, NT_CHILDNODEDEFINITION, NAME);
+ }
ndt.writeTo(tree);
}
}
+ tree = type.getChild(JCR_CHILDNODEDEFINITION + "[" + ndn++ + "]");
+ while (tree.exists()) {
+ tree.remove();
+ tree = type.getChild(JCR_CHILDNODEDEFINITION + "[" + ndn++ + "]");
+ }
return type;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/PropertyDefinitionTemplateImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/PropertyDefinitionTemplateImpl.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/PropertyDefinitionTemplateImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/PropertyDefinitionTemplateImpl.java
Mon Jan 20 19:45:09 2014
@@ -24,6 +24,7 @@ import static org.apache.jackrabbit.JcrC
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_AVAILABLE_QUERY_OPERATORS;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_FULLTEXT_SEARCHABLE;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_QUERY_ORDERABLE;
+import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.RESIDUAL_NAME;
import java.util.Arrays;
@@ -34,6 +35,7 @@ import javax.jcr.nodetype.ConstraintViol
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.nodetype.PropertyDefinitionTemplate;
import javax.jcr.query.qom.QueryObjectModelConstants;
+import javax.jcr.version.OnParentVersionAction;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
@@ -109,11 +111,15 @@ class PropertyDefinitionTemplateImpl ext
tree.setProperty(
JCR_VALUECONSTRAINTS,
Arrays.asList(valueConstraints), Type.STRINGS);
+ } else {
+ tree.removeProperty(JCR_VALUECONSTRAINTS);
}
if (defaultValues != null) {
tree.setProperty(PropertyStates.createProperty(
JCR_DEFAULTVALUES, Arrays.asList(defaultValues)));
+ } else {
+ tree.removeProperty(JCR_DEFAULTVALUES);
}
}
@@ -205,8 +211,33 @@ class PropertyDefinitionTemplateImpl ext
//------------------------------------------------------------< Object >--
+ @Override
public String toString() {
- return String.format("PropertyDefinitionTemplate(%s)", getOakName());
+ StringBuilder builder = new StringBuilder("- ");
+ if (getOakName() == null) {
+ builder.append(RESIDUAL_NAME);
+ } else {
+ builder.append(getOakName());
+ }
+ if (requiredType != PropertyType.STRING) {
+ builder.append(" (");
+ builder.append(Type.fromTag(requiredType, false).toString());
+ builder.append(")");
+ }
+ if (isAutoCreated()) {
+ builder.append(" a");
+ }
+ if (isProtected()) {
+ builder.append(" p");
+ }
+ if (isMandatory()) {
+ builder.append(" m");
+ }
+ if (getOnParentVersion() != OnParentVersionAction.COPY) {
+ builder.append(" ");
+
builder.append(OnParentVersionAction.nameFromValue(getOnParentVersion()));
+ }
+ return builder.toString();
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ReadWriteNodeTypeManager.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ReadWriteNodeTypeManager.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ReadWriteNodeTypeManager.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ReadWriteNodeTypeManager.java
Mon Jan 20 19:45:09 2014
@@ -128,8 +128,6 @@ public abstract class ReadWriteNodeTypeM
public final NodeTypeIterator registerNodeTypes(
NodeTypeDefinition[] ntds, boolean allowUpdate)
throws RepositoryException {
- // TODO proper node type registration... (OAK-66, OAK-411)
- // TODO handle inter-type dependencies (OAK-66, OAK-411)
Root root = getWriteRoot();
try {
Tree tree = getOrCreateNodeTypes(root);
Modified:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/nodetype/NodeTypeTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/nodetype/NodeTypeTest.java?rev=1559816&r1=1559815&r2=1559816&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/nodetype/NodeTypeTest.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/nodetype/NodeTypeTest.java
Mon Jan 20 19:45:09 2014
@@ -20,11 +20,16 @@ package org.apache.jackrabbit.oak.jcr.no
import static junit.framework.Assert.fail;
+import java.util.List;
+
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeTypeDefinition;
import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
import org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest;
import org.apache.jackrabbit.oak.jcr.NodeStoreFixture;
@@ -66,6 +71,55 @@ public class NodeTypeTest extends Abstra
}
@Test
+ public void updateNodeType() throws Exception {
+ Session session = getAdminSession();
+ Node root = session.getRootNode();
+ ValueFactory vf = session.getValueFactory();
+ NodeTypeManager manager = session.getWorkspace().getNodeTypeManager();
+
+ Node n = root.addNode("q1", "nt:query");
+ n.setProperty("jcr:statement", vf.createValue("statement"));
+ session.save();
+
+ NodeTypeDefinition ntd = manager.getNodeType("nt:query");
+ NodeTypeTemplate ntt = manager.createNodeTypeTemplate(ntd);
+
+ try {
+ manager.registerNodeType(ntt, true);
+ // no changes to the type, so the registration should be a no-op
+ } catch (ConstraintViolationException unexpected) {
+ fail();
+ }
+
+ // make the (still missing) jcr:language property mandatory
+ @SuppressWarnings("unchecked")
+ List<PropertyDefinitionTemplate> pdts =
ntt.getPropertyDefinitionTemplates();
+ for (PropertyDefinitionTemplate pdt : pdts) {
+ if ("jcr:language".equals(pdt.getName())) {
+ pdt.setMandatory(true);
+ }
+ }
+
+ try {
+ manager.registerNodeType(ntt, true);
+ fail();
+ } catch (ConstraintViolationException expected) {
+ // the registration fails because of the would-be invalid content
+ }
+
+ // add the jcr:language property so it can be made mandatory
+ n.setProperty("jcr:language", vf.createValue("language"));
+ session.save();
+
+ try {
+ manager.registerNodeType(ntt, true);
+ // now the mandatory property exists, so the type change is OK
+ } catch (ConstraintViolationException unexpected) {
+ fail();
+ }
+ }
+
+ @Test
public void removeNodeType() throws Exception {
Session session = getAdminSession();
Node root = session.getRootNode();