Author: bcarothers
Date: 2009-06-13 11:56:00 -0400 (Sat, 13 Jun 2009)
New Revision: 1049
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
Log:
Committed most of unregisterTypes method. Still need to add check that the type is not in
use on any nodes, but this should be much easier after queries are implemented. Leaving
this open until that piece of the issue is corrected.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-06-12 01:28:17 UTC
(rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-06-13 15:56:00 UTC
(rev 1049)
@@ -115,6 +115,7 @@
// Type registration messages
public static I18n invalidNodeTypeName;
+ public static I18n noSuchNodeType;
public static I18n nodeTypeAlreadyExists;
public static I18n invalidPrimaryTypeName;
public static I18n invalidSupertypeName;
@@ -139,6 +140,10 @@
public static I18n nodeNotReferenceable;
public static I18n noPendingChangesAllowed;
+ public static I18n cannotUnregisterSupertype;
+ public static I18n cannotUnregisterRequiredPrimaryType;
+ public static I18n cannotUnregisterDefaultPrimaryType;
+
static {
try {
I18n.initialize(JcrI18n.class);
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-06-12 01:28:17 UTC
(rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-06-13 15:56:00 UTC
(rev 1049)
@@ -94,5 +94,4 @@
public void remove() throws RepositoryException {
editorForParent().destroyChild(nodeUuid);
}
-
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-06-12 01:28:17 UTC
(rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-06-13 15:56:00 UTC
(rev 1049)
@@ -165,6 +165,10 @@
return thisAndAllSupertypes;
}
+ List<JcrNodeType> supertypes() {
+ return allSupertypes;
+ }
+
/**
* Get the child definitions defined on this node type (excluding inherited
definitions).
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-06-12
01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-06-13
15:56:00 UTC (rev 1049)
@@ -39,6 +39,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.jcr.nodetype.InvalidNodeTypeDefinitionException;
import org.jboss.dna.jcr.nodetype.NodeDefinitionTemplate;
import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
@@ -416,6 +417,32 @@
}
/**
+ * Allows the collection of node types to be unregistered if they are not referenced
by other node types as supertypes,
+ * default primary types of child nodes, or required primary types of child nodes.
+ * <p>
+ * <b>NOTE: This method does not check to see if any of the node types are
currently being used. Unregistering a node type
+ * that is being used will cause the system to become unstable</b>
+ * </p>
+ *
+ * @param nodeTypeNames the names of the node types to be unregistered
+ * @throws NoSuchNodeTypeException if any of the node type names do not correspond to
a registered node type
+ * @throws InvalidNodeTypeDefinitionException if any of the node types with the given
names cannot be unregistered because
+ * they are the supertype, one of the required primary types, or a default
primary type of a node type that is not
+ * being unregistered.
+ * @throws RepositoryException if any other error occurs
+ */
+ public void unregisterNodeType( Collection<String> nodeTypeNames )
+ throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException,
RepositoryException {
+ NameFactory nameFactory = this.context.getValueFactories().getNameFactory();
+
+ Collection<Name> names = new ArrayList<Name>(nodeTypeNames.size());
+ for (String name : nodeTypeNames) {
+ names.add(nameFactory.create(name));
+ }
+ repositoryTypeManager.unregisterNodeType(names);
+ }
+
+ /**
* Returns an empty {@code NodeTypeTemplate} which can then be used to define a node
type and passed to
* {@link JcrNodeTypeManager#registerNodeType(NodeTypeDefinition, boolean)}
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
===================================================================
---
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-06-12
01:28:17 UTC (rev 1048)
+++
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-06-13
15:56:00 UTC (rev 1049)
@@ -38,6 +38,7 @@
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
@@ -46,6 +47,7 @@
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.common.text.XmlNameEncoder;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.Location;
@@ -1100,6 +1102,89 @@
}
/**
+ * Allows the collection of node types to be unregistered if they are not referenced
by other node types as supertypes,
+ * default primary types of child nodes, or required primary types of child nodes.
+ * <p>
+ * <b>NOTE: This method does not check to see if any of the node types are
currently being used. Unregistering a node type
+ * that is being used will cause the system to become unstable</b>
+ * </p>
+ *
+ * @param nodeTypeNames the names of the node types to be unregistered
+ * @throws NoSuchNodeTypeException if any of the node type names do not correspond to
a registered node type
+ * @throws InvalidNodeTypeDefinitionException if any of the node types with the given
names cannot be unregistered because
+ * they are the supertype, one of the required primary types, or a default
primary type of a node type that is not
+ * being unregistered.
+ * @throws RepositoryException if any other error occurs
+ */
+ void unregisterNodeType( Collection<Name> nodeTypeNames )
+ throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException,
RepositoryException {
+ CheckArg.isNotNull(nodeTypeNames, "nodeTypeNames");
+ try {
+ /*
+ * Grab an exclusive lock on this data to keep other nodes from being
added/saved while the unregistration checks are occurring
+ */
+ nodeTypeManagerLock.writeLock().lock();
+
+ for (Name nodeTypeName : nodeTypeNames) {
+ /*
+ * Check that the type names are valid
+ */
+ if (nodeTypeName == null) {
+ throw new
NoSuchNodeTypeException(JcrI18n.invalidNodeTypeName.text());
+ }
+ String name = nodeTypeName.getString(context.getNamespaceRegistry());
+
+ if (!this.nodeTypes.containsKey(nodeTypeName)) {
+ throw new
NoSuchNodeTypeException(JcrI18n.noSuchNodeType.text(name));
+ }
+
+ /*
+ * Check that no other node definitions have dependencies on any of the
named types
+ */
+ for (JcrNodeType nodeType : nodeTypes.values()) {
+ // If this node is also being unregistered, don't run checks
against it
+ if (nodeTypeNames.contains(nodeType.getInternalName())) {
+ continue;
+ }
+
+ for (JcrNodeType supertype : nodeType.supertypes()) {
+ if (nodeTypeName.equals(supertype.getInternalName())) {
+ throw new InvalidNodeTypeDefinitionException(
+
JcrI18n.cannotUnregisterSupertype.text(name,
+
supertype.getName()));
+ }
+ }
+
+ for (JcrNodeDefinition childNode : nodeType.childNodeDefinitions())
{
+ NodeType defaultPrimaryType = childNode.getDefaultPrimaryType();
+ if (defaultPrimaryType != null &&
name.equals(defaultPrimaryType.getName())) {
+ throw new InvalidNodeTypeDefinitionException(
+
JcrI18n.cannotUnregisterDefaultPrimaryType.text(name,
+
nodeType.getName(),
+
childNode.getName()));
+ }
+ if
(childNode.getRequiredPrimaryTypeNames().contains(nodeTypeName)) {
+ throw new InvalidNodeTypeDefinitionException(
+
JcrI18n.cannotUnregisterRequiredPrimaryType.text(name,
+
nodeType.getName(),
+
childNode.getName()));
+ }
+ }
+ }
+ }
+
+ /*
+ * Do a full recursive search over the content graph to make sure that this
type isn't being used
+ */
+ // TODO: replace this with a query after queries work
+ this.nodeTypes.keySet().removeAll(nodeTypeNames);
+
+ } finally {
+ nodeTypeManagerLock.writeLock().unlock();
+ }
+ }
+
+ /**
* Registers a new node type or updates an existing node type using the specified
definition and returns the resulting {@code
* NodeType} object.
* <p>
@@ -1803,15 +1888,13 @@
for (JcrNodeDefinition ancestor : ancestors) {
if (ancestor.isProtected()) {
throw new InvalidNodeTypeDefinitionException(
-
JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
-
.getName(),
+
JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
"child node"));
}
if (ancestor.isMandatory() && !node.isMandatory()) {
throw new InvalidNodeTypeDefinitionException(
-
JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
-
.getName(),
+
JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
"child node"));
}
@@ -1876,16 +1959,15 @@
Value[] defaultValues = prop.getDefaultValues();
if (prop.isAutoCreated() && !prop.isProtected() && (defaultValues
== null || defaultValues.length == 0)) {
- throw new
InvalidNodeTypeDefinitionException(JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
-
prop.getDeclaringNodeType()
-
.getName()));
+ throw new InvalidNodeTypeDefinitionException(
+
JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
+
prop.getDeclaringNodeType().getName()));
}
if (!prop.isMultiple() && (defaultValues != null &&
defaultValues.length > 1)) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.singleValuedPropertyNeedsSingleValuedDefault.text(prop.getName(),
-
prop.getDeclaringNodeType()
-
.getName()));
+
prop.getDeclaringNodeType().getName()));
}
Name propName =
context.getValueFactories().getNameFactory().create(prop.getName());
@@ -1899,15 +1981,13 @@
for (JcrPropertyDefinition ancestor : ancestors) {
if (ancestor.isProtected()) {
throw new InvalidNodeTypeDefinitionException(
-
JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
-
.getName(),
+
JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
"property"));
}
if (ancestor.isMandatory() && !prop.isMandatory()) {
throw new InvalidNodeTypeDefinitionException(
-
JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
-
.getName(),
+
JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
"property"));
}
@@ -1918,16 +1998,14 @@
&& !Arrays.equals(ancestor.getValueConstraints(),
prop.getValueConstraints())) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.constraintsChangedInSubtype.text(propName,
-
ancestor.getDeclaringNodeType()
-
.getName()));
+
ancestor.getDeclaringNodeType().getName()));
}
if (!isAlwaysSafeConversion(prop.getRequiredType(),
ancestor.getRequiredType())) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.cannotRedefineProperty.text(propName,
PropertyType.nameFromValue(prop.getRequiredType()),
-
ancestor.getDeclaringNodeType()
-
.getName(),
+
ancestor.getDeclaringNodeType().getName(),
PropertyType.nameFromValue(ancestor.getRequiredType())));
}
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-06-12
01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-06-13
15:56:00 UTC (rev 1049)
@@ -100,6 +100,7 @@
invalidQueryLanguage="{0}" is not a valid query langauge. Supported languages
are\: {1}
invalidNodeTypeName=Node types cannot have a null or empty name
+noSuchNodeType=Type named '{0}' does not exist
nodeTypeAlreadyExists=Node type '{0}' already exists
invalidPrimaryTypeName=Required primary type '{0}' in type '{1}' does not
exist
invalidSupertypeName=Supertype '{0}' from type '{1}' does not exist
@@ -123,3 +124,7 @@
nodeNotReferenceable=Only referenceable nodes may be the value of reference properties
noPendingChangesAllowed=This operation cannot be performed when the session has pending
changes
+
+cannotUnregisterSupertype=Cannot unregister type '{0}' which is supertype of type
'{1}'
+cannotUnregisterRequiredPrimaryType=Cannot unregister type '{0}' which is the
required primary type for child node '{2}' on type '{1}'
+cannotUnregisterDefaultPrimaryType=Cannot unregister type '{0}' which is the
default primary type for child node '{2}' of type '{1}'
\ No newline at end of file
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-06-12
01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-06-13
15:56:00 UTC (rev 1049)
@@ -25,12 +25,15 @@
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.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.graph.ExecutionContext;
@@ -41,6 +44,7 @@
import org.jboss.dna.jcr.nodetype.NodeDefinitionTemplate;
import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
import org.jboss.dna.jcr.nodetype.NodeTypeExistsException;
+import org.jboss.dna.jcr.nodetype.NodeTypeTemplate;
import org.jboss.dna.jcr.nodetype.PropertyDefinitionTemplate;
import org.junit.Before;
import org.junit.Test;
@@ -703,6 +707,103 @@
compareTemplatesToNodeTypes(templates,
repoTypeManager.registerNodeTypes(templates, false));
}
+ /*
+ * Unregistration tests
+ */
+
+ @Test (expected=IllegalArgumentException.class)
+ public void shouldNotAllowUnregisteringNullCollection() throws Exception {
+ repoTypeManager.unregisterNodeType(null);
+ }
+
+ @Test (expected=NoSuchNodeTypeException.class)
+ public void shouldNotAllowUnregisteringInvalidTypeNames() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE,
JcrLexicon.DATA}));
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringSupertype() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {
JcrNtLexicon.HIERARCHY_NODE, }));
+
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringRequiredPrimaryType() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {
JcrNtLexicon.FROZEN_NODE, }));
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringDefaultPrimaryType() throws Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new
JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
+ ntTemplate.getNodeDefinitionTemplates().add(childNode);
+
+ try {
+ repoTypeManager.registerNodeType(ntTemplate, false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE,
}));
+ }
+
+ @Test
+ public void shouldAllowUnregisteringUnusedType() throws Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new
JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
+ ntTemplate.getNodeDefinitionTemplates().add(childNode);
+
+ try {
+ repoTypeManager.registerNodeType(ntTemplate, false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
+ int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName
}));
+ assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 1));
+ assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowUnregisteringUnusedTypesWithMutualDependencies() throws
Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new
JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(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.setDefaultPrimaryType(TEST_TYPE_NAME);
+ ntTemplate2.getNodeDefinitionTemplates().add(childNode2);
+
+ try {
+ repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {
ntTemplate, ntTemplate2 }), false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
+ Name type2NameAsName = nameFactory.create(TEST_TYPE_NAME2);
+ int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName,
type2NameAsName }));
+ assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 2));
+ assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
+ assertThat(repoTypeManager.getNodeType(type2NameAsName), is(nullValue()));
+
+ }
+
private void compareTemplatesToNodeTypes( List<NodeTypeDefinition> templates,
List<JcrNodeType> nodeTypes ) {
assertThat(templates.size(), is(nodeTypes.size()));
@@ -826,4 +927,5 @@
// assertThat(template.getRequiredPrimaryTypeNames(),
is(definition.getRequiredPrimaryTypeNames()));
}
+
}