Index: modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java (revision 2107) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java (working copy) @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -240,7 +241,7 @@ class GraphNodeTypeReader implements Iterable { Destination destination = new GraphBatchDestination(batch); try { importFrom(destination, root, content, resourceName); - List types = readTypesFrom(graph, root); + List types = readTypesFrom(graph, root, null); this.types.addAll(types); } catch (Throwable t) { problems.addError(t, JcrI18n.errorImportingNodeTypeContent, (Object)resourceName, t.getMessage()); @@ -258,7 +259,23 @@ class GraphNodeTypeReader implements Iterable { public void read( Graph graph, Path parentOfTypes, String resourceName ) { - this.types.addAll(readTypesFrom(graph, parentOfTypes)); + this.types.addAll(readTypesFrom(graph, parentOfTypes, null)); + } + + /** + * Import the node types from the supplied location in the specified graph. + * + * @param graph the graph containing the standard ModeShape CND content + * @param parentOfTypes the path to the parent of the node type definition nodes + * @param nodeTypesToRead the names of the node types that should be read; null means that all node types should be read + * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no + * useful name + */ + public void read( Graph graph, + Path parentOfTypes, + Collection nodeTypesToRead, + String resourceName ) { + this.types.addAll(readTypesFrom(graph, parentOfTypes, nodeTypesToRead)); } /** @@ -272,7 +289,7 @@ class GraphNodeTypeReader implements Iterable { public void read( Subgraph subgraph, Location locationOfParent, String resourceName ) { - this.types.addAll(readTypesFrom(subgraph, locationOfParent)); + this.types.addAll(readTypesFrom(subgraph, locationOfParent, null)); } /** @@ -304,19 +321,28 @@ class GraphNodeTypeReader implements Iterable { } protected List readTypesFrom( Graph graph, - Path parentOfTypes ) { + Path parentOfTypes, + Collection nodeTypesToRead ) { Subgraph subgraph = graph.getSubgraphOfDepth(5).at(parentOfTypes); - return readTypesFrom(subgraph, subgraph.getLocation()); + return readTypesFrom(subgraph, subgraph.getLocation(), nodeTypesToRead); } protected List readTypesFrom( Subgraph nodeTypeSubgraph, - Location locationOfParentOfNodeTypes ) { + Location locationOfParentOfNodeTypes, + Collection nodeTypesToRead ) { List nodeTypeLocations = nodeTypeSubgraph.getNode(locationOfParentOfNodeTypes).getChildren(); List results = new ArrayList(nodeTypeLocations.size()); + boolean shouldFilterNodes = locationOfParentOfNodeTypes.hasPath() && nodeTypesToRead != null; for (Location location : nodeTypeLocations) { SubgraphNode nodeTypeNode = nodeTypeSubgraph.getNode(location); assert location.getPath() != null; + + Path relativeNodeTypePath = shouldFilterNodes ? location.getPath().relativeTo(locationOfParentOfNodeTypes.getPath()) : null; + if (shouldFilterNodes && !nodeTypesToRead.contains(relativeNodeTypePath.getSegment(0).getName())) { + continue; + } + try { NodeTypeDefinition nodeType = nodeTypeFrom(nodeTypeNode, nodeTypeSubgraph); results.add(nodeType); Index: modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (revision 2107) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (working copy) @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -2245,7 +2246,8 @@ class RepositoryNodeTypeManager implements JcrSystemObserver { @Override public void notify( Changes changes ) { - boolean needsReload = false; + Collection createdNodeTypeNames = new HashSet(); + Collection deletedNodeTypeNames = new HashSet(); for (ChangeRequest change : changes.getChangeRequests()) { assert change.changedLocation().hasPath(); @@ -2257,10 +2259,29 @@ class RepositoryNodeTypeManager implements JcrSystemObserver { } assert nodeTypesPath.isAncestorOf(changedPath); + /* + * The first segment under the node types root (as stored in nodeTypesPath) must be + * the node type name. + */ + Path relativePath = changedPath.relativeTo(nodeTypesPath); + Name changedNodeTypeName = relativePath.getSegment(0).getName(); + switch (change.getType()) { case CREATE_NODE: + /* + * Registering one node type can result in many CreateNodeRequests + * being created (1 for the type, 1 for each property, 1 for each child node), but + * if anything is changed on the node type, the whole node type needs to be reloaded + * anyway. + * + */ + if (!createdNodeTypeNames.contains(changedNodeTypeName)) { + createdNodeTypeNames.add(changedNodeTypeName); + } + break; + case DELETE_BRANCH: - needsReload = true; + deletedNodeTypeNames.add(changedNodeTypeName); break; default: @@ -2268,14 +2289,14 @@ class RepositoryNodeTypeManager implements JcrSystemObserver { } } - if (!needsReload) return; + if (createdNodeTypeNames.isEmpty() && deletedNodeTypeNames.isEmpty()) return; this.nodeTypeManagerLock.writeLock().lock(); try { GraphNodeTypeReader reader = new GraphNodeTypeReader(this.context); Graph systemGraph = repository.createSystemGraph(this.context); - reader.read(systemGraph, nodeTypesPath, null); + reader.read(systemGraph, nodeTypesPath, createdNodeTypeNames, null); Problems readerProblems = reader.getProblems(); if (readerProblems.hasProblems()) { @@ -2299,7 +2320,10 @@ class RepositoryNodeTypeManager implements JcrSystemObserver { LOGGER.error(JcrI18n.errorSynchronizingNodeTypes, re); } - this.nodeTypes.clear(); + assert this.nodeTypes.get(ModeShapeLexicon.ROOT) != null; + assert !deletedNodeTypeNames.contains(ModeShapeLexicon.ROOT); + + nodeTypes.keySet().removeAll(deletedNodeTypeNames); this.nodeTypes.putAll(newNodeTypeMap); assert this.nodeTypes.get(ModeShapeLexicon.ROOT) != null;