Index: modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java
===================================================================
--- modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java (revision 2072)
+++ modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java (working copy)
@@ -25,7 +25,9 @@ package org.modeshape.test.integration;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
@@ -34,10 +36,16 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Node;
+import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
@@ -51,6 +59,7 @@ import org.modeshape.connector.store.jpa.JpaSource;
import org.modeshape.jcr.JcrConfiguration;
import org.modeshape.jcr.JcrEngine;
import org.modeshape.jcr.ModeShapeRoles;
+import org.modeshape.jcr.NodeTypeAssertion;
import org.modeshape.jcr.JcrRepository.Option;
public class ClusteringTest {
@@ -62,7 +71,7 @@ public class ClusteringTest {
private static List sessions = new ArrayList();
@BeforeClass
- public static void beforeEach() throws Exception {
+ public static void beforeAll() throws Exception {
// Delete the database files, if there are any ...
FileUtil.delete("target/db");
@@ -295,6 +304,88 @@ public class ClusteringTest {
assertThat(session3.getNode(path).getProperty(propName).getString(), is(propValue));
}
+ @Test
+ public void shouldPropagateTypeUnregistrationAcrossCluster() throws Exception {
+ Session session1 = sessionFrom(engine1);
+ Session session2 = sessionFrom(engine2);
+ Session session3 = sessionFrom(engine3);
+
+ NodeTypeManager typeManager1 = session1.getWorkspace().getNodeTypeManager();
+ NodeTypeManager typeManager2 = session2.getWorkspace().getNodeTypeManager();
+ NodeTypeManager typeManager3 = session3.getWorkspace().getNodeTypeManager();
+
+ final String NODE_TYPE_NAME = "nt:file";
+
+ typeManager1.unregisterNodeType(NODE_TYPE_NAME);
+ assertFalse(typeManager1.hasNodeType(NODE_TYPE_NAME));
+
+ for (int i = 0; i < 50; i++) {
+ try {
+ if (!typeManager2.hasNodeType(NODE_TYPE_NAME) && !typeManager3.hasNodeType(NODE_TYPE_NAME)) break;
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ return;
+ }
+ }
+
+ assertFalse(typeManager2.hasNodeType(NODE_TYPE_NAME));
+ assertFalse(typeManager3.hasNodeType(NODE_TYPE_NAME));
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Test
+ public void shouldPropagateTypeRegistrationAcrossCluster() throws Exception {
+ Session session1 = sessionFrom(engine1);
+ Session session2 = sessionFrom(engine2);
+ Session session3 = sessionFrom(engine3);
+
+ NodeTypeManager typeManager1 = session1.getWorkspace().getNodeTypeManager();
+ NodeTypeManager typeManager2 = session2.getWorkspace().getNodeTypeManager();
+ NodeTypeManager typeManager3 = session3.getWorkspace().getNodeTypeManager();
+
+ final String NODE_TYPE_NAME = "mode:newType";
+ NodeTypeTemplate nodeType = typeManager1.createNodeTypeTemplate();
+ nodeType.setName(NODE_TYPE_NAME);
+ nodeType.setMixin(true);
+ nodeType.setDeclaredSuperTypeNames(new String[] {"mix:referenceable"});
+ nodeType.setOrderableChildNodes(true);
+ nodeType.setQueryable(true);
+
+ PropertyDefinitionTemplate prop = typeManager1.createPropertyDefinitionTemplate();
+ prop.setName("prop");
+ prop.setAvailableQueryOperators(new String[] {"="});
+ prop.setMultiple(true);
+ prop.setRequiredType(PropertyType.STRING);
+ nodeType.getPropertyDefinitionTemplates().add(prop);
+
+ NodeDefinitionTemplate child = typeManager1.createNodeDefinitionTemplate();
+ child.setName("child");
+ child.setSameNameSiblings(true);
+ nodeType.getNodeDefinitionTemplates().add(child);
+
+ typeManager1.registerNodeType(nodeType, false);
+ assertTrue(typeManager1.hasNodeType(NODE_TYPE_NAME));
+ NodeType nodeType1 = typeManager1.getNodeType(NODE_TYPE_NAME);
+
+ for (int i = 0; i < 50; i++) {
+ try {
+ if (typeManager2.hasNodeType(NODE_TYPE_NAME) && typeManager3.hasNodeType(NODE_TYPE_NAME)) break;
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ return;
+ }
+ }
+
+ assertTrue(typeManager2.hasNodeType(NODE_TYPE_NAME));
+ assertTrue(typeManager3.hasNodeType(NODE_TYPE_NAME));
+
+ NodeTypeTemplate template2 = typeManager2.createNodeTypeTemplate(typeManager2.getNodeType(NODE_TYPE_NAME));
+ NodeTypeTemplate template3 = typeManager3.createNodeTypeTemplate(typeManager3.getNodeType(NODE_TYPE_NAME));
+
+ NodeTypeAssertion.compareTemplateToNodeType(template2, nodeType1);
+ NodeTypeAssertion.compareTemplateToNodeType(template3, nodeType1);
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// Utility Methods
// ----------------------------------------------------------------------------------------------------------------
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/GraphNodeTypeReader.java (working copy)
@@ -105,7 +105,7 @@ import org.modeshape.graph.property.basic.LocalNamespaceRegistry;
*
*/
@NotThreadSafe
-abstract class GraphNodeTypeReader implements Iterable {
+class GraphNodeTypeReader implements Iterable {
private static final Map PROPERTY_TYPE_VALUES_FROM_NAME;
@@ -321,6 +321,7 @@ abstract class GraphNodeTypeReader implements Iterable {
NodeTypeDefinition nodeType = nodeTypeFrom(nodeTypeNode, nodeTypeSubgraph);
results.add(nodeType);
} catch (ConstraintViolationException e) {
+ e.printStackTrace();
String resource = stringFactory.create(locationOfParentOfNodeTypes.getPath());
problems.addError(e, JcrI18n.errorImportingNodeTypeContent, resource, e.getMessage());
}
@@ -373,6 +374,8 @@ abstract class GraphNodeTypeReader implements Iterable {
JcrLexicon.ON_PARENT_VERSION,
OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY));
int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName);
+
+ String requiredTypeName = readString(propertyDefinitionNode, JcrLexicon.REQUIRED_TYPE, null);
int requiredType = PROPERTY_TYPE_VALUES_FROM_NAME.get(readString(propertyDefinitionNode, JcrLexicon.REQUIRED_TYPE, null));
boolean mandatory = readBoolean(propertyDefinitionNode, JcrLexicon.MANDATORY, false);
@@ -386,7 +389,9 @@ abstract class GraphNodeTypeReader implements Iterable {
List queryOps = readStrings(propertyDefinitionNode, JcrLexicon.QUERY_OPERATORS);
PropertyDefinitionTemplate template = new JcrPropertyDefinitionTemplate(context);
- template.setName(name);
+ if (name != null) {
+ template.setName(name);
+ }
template.setAutoCreated(autoCreated);
template.setMandatory(mandatory);
template.setMultiple(multiple);
@@ -420,7 +425,9 @@ abstract class GraphNodeTypeReader implements Iterable {
List requiredTypes = readStrings(childNodeDefinitionNode, JcrLexicon.REQUIRED_PRIMARY_TYPES);
NodeDefinitionTemplate template = new JcrNodeDefinitionTemplate(context);
- template.setName(childNodeName);
+ if (childNodeName != null) {
+ template.setName(childNodeName);
+ }
template.setAutoCreated(autoCreated);
template.setMandatory(mandatory);
template.setSameNameSiblings(allowsSns);
@@ -541,15 +548,17 @@ abstract class GraphNodeTypeReader implements Iterable {
/**
* Method that loads into the graph destination the content containing the node type definitions.
*
- * @param graphDestination
- * @param path
- * @param content
- * @param resourceName
+ * @param graphDestination the destination to which the node type content should be written; never null
+ * @param path the path within the destination at which the node type content should be rooted; never null
+ * @param content the content containing some string representation of the node types to be imported; never null
+ * @param resourceName a descriptive name for this import (used only for error messages); may be null
* @throws Exception if there is a problem importing from the content; this will be automatically recorded in the problems
*/
- protected abstract void importFrom( Destination graphDestination,
- Path path,
- String content,
- String resourceName ) throws Exception;
+ protected void importFrom( Destination graphDestination,
+ Path path,
+ String content,
+ String resourceName ) throws Exception {
+ throw new UnsupportedOperationException();
+ }
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (working copy)
@@ -200,6 +200,10 @@ public final class JcrI18n {
public static I18n primaryTypeCannotBeAbstract;
public static I18n setPrimaryTypeNotSupported;
+ public static I18n errorReadingNodeTypesFromRemote;
+ public static I18n problemReadingNodeTypesFromRemote;
+ public static I18n errorSynchronizingNodeTypes;
+
// Lock messages
public static I18n nodeNotLockable;
public static I18n cannotRemoveLockToken;
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNodeTypeManager.java (working copy)
@@ -91,6 +91,10 @@ public class JcrNodeTypeManager implements NodeTypeManager {
this.schemata = null;
}
+ void signalExternalNodeTypeChanges() {
+ this.schemata = null;
+ }
+
/**
* {@inheritDoc}
*
@@ -207,6 +211,7 @@ public class JcrNodeTypeManager implements NodeTypeManager {
for (NodeDefinition definition : repositoryTypeManager.getNodeType(ModeShapeLexicon.ROOT).getChildNodeDefinitions()) {
if (definition.getName().equals(JcrNodeType.RESIDUAL_ITEM_NAME)) return (JcrNodeDefinition)definition;
}
+
assert false; // should not get here
return null;
}
@@ -672,13 +677,15 @@ public class JcrNodeTypeManager implements NodeTypeManager {
JcrNodeDefinitionTemplate ndt = new JcrNodeDefinitionTemplate(context());
ndt.setAutoCreated(nodeDefinition.isAutoCreated());
- ndt.setDefaultPrimaryType(ndt.getDefaultPrimaryTypeName());
- ndt.setMandatory(ndt.isMandatory());
- ndt.setName(ndt.getName());
- ndt.setOnParentVersion(ndt.getOnParentVersion());
- ndt.setProtected(ndt.isProtected());
- ndt.setRequiredPrimaryTypeNames(ndt.getRequiredPrimaryTypeNames());
- ndt.setSameNameSiblings(ndt.allowsSameNameSiblings());
+ ndt.setDefaultPrimaryType(nodeDefinition.getDefaultPrimaryTypeName());
+ ndt.setMandatory(nodeDefinition.isMandatory());
+ if (nodeDefinition.getName() != null) {
+ ndt.setName(nodeDefinition.getName());
+ }
+ ndt.setOnParentVersion(nodeDefinition.getOnParentVersion());
+ ndt.setProtected(nodeDefinition.isProtected());
+ ndt.setRequiredPrimaryTypeNames(nodeDefinition.getRequiredPrimaryTypeNames());
+ ndt.setSameNameSiblings(nodeDefinition.allowsSameNameSiblings());
ntt.getNodeDefinitionTemplates().add(ndt);
}
@@ -692,7 +699,9 @@ public class JcrNodeTypeManager implements NodeTypeManager {
pdt.setFullTextSearchable(propertyDefinition.isFullTextSearchable());
pdt.setMandatory(propertyDefinition.isMandatory());
pdt.setMultiple(propertyDefinition.isMultiple());
- pdt.setName(propertyDefinition.getName());
+ if (propertyDefinition.getName() != null) {
+ pdt.setName(propertyDefinition.getName());
+ }
pdt.setOnParentVersion(propertyDefinition.getOnParentVersion());
pdt.setProtected(propertyDefinition.isProtected());
pdt.setQueryOrderable(propertyDefinition.isQueryOrderable());
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (working copy)
@@ -299,7 +299,7 @@ public class JcrRepository implements Repository {
/**
* The default value for the {@link Option#PROJECT_NODE_TYPES} option is {@value} .
*/
- public static final String PROJECT_NODE_TYPES = Boolean.FALSE.toString();
+ public static final String PROJECT_NODE_TYPES = Boolean.TRUE.toString();
/**
* The default value for the {@link Option#JAAS_LOGIN_CONFIG_NAME} option is {@value} .
@@ -416,10 +416,6 @@ public class JcrRepository implements Repository {
private final RepositoryObservationManager repositoryObservationManager;
private final SecurityContext anonymousUserContext;
private final QueryParsers queryParsers;
- /**
- * Immutable collection of objects observing changes to the system graph
- */
- private final Collection jcrSystemObservers;
// Until the federated connector supports queries, we have to use a search engine ...
private final RepositoryQueryManager queryManager;
@@ -557,10 +553,17 @@ public class JcrRepository implements Repository {
}
// Set up the repository type manager ...
+ Path parentOfTypeNodes = null;
+
+ if (Boolean.valueOf(this.options.get(Option.PROJECT_NODE_TYPES))) {
+ parentOfTypeNodes = pathFactory.create(systemPath, JcrLexicon.NODE_TYPES);
+ }
+
try {
boolean includeInheritedProperties = Boolean.valueOf(this.options.get(Option.TABLES_INCLUDE_COLUMNS_FOR_INHERITED_PROPERTIES));
+
// this.repositoryTypeManager = new RepositoryNodeTypeManager(this, includeInheritedProperties);
- this.repositoryTypeManager = new RepositoryNodeTypeManager(this, includeInheritedProperties);
+ this.repositoryTypeManager = new RepositoryNodeTypeManager(this, parentOfTypeNodes, includeInheritedProperties);
CndNodeTypeReader nodeTypeReader = new CndNodeTypeReader(this.executionContext);
nodeTypeReader.readBuiltInTypes();
this.repositoryTypeManager.registerNodeTypes(nodeTypeReader);
@@ -572,11 +575,6 @@ public class JcrRepository implements Repository {
throw new IllegalStateException("Could not access node type definition files", ioe);
}
if (WORKSPACES_SHARE_SYSTEM_BRANCH) {
- if (Boolean.valueOf(this.options.get(Option.PROJECT_NODE_TYPES))) {
- // Note that the node types are written directly to the system workspace.
- Path parentOfTypeNodes = pathFactory.create(systemPath, JcrLexicon.NODE_TYPES);
- this.repositoryTypeManager.projectOnto(systemGraph, parentOfTypeNodes);
- }
// Create the projection for the system repository ...
ProjectionParser projectionParser = ProjectionParser.getInstance();
@@ -729,11 +727,9 @@ public class JcrRepository implements Repository {
};
// Define the set of "/jcr:system" observers ...
- this.jcrSystemObservers = Collections.unmodifiableList(Arrays.asList(new JcrSystemObserver[] {repositoryLockManager,
- namespaceObserver}));
-
// This observer picks up notification of changes to the system graph in a cluster. It's a NOP if there is no cluster.
- this.repositoryObservationManager.register(new SystemChangeObserver());
+ repositoryObservationManager.register(new SystemChangeObserver(Arrays.asList(new JcrSystemObserver[] {
+ repositoryLockManager, namespaceObserver, repositoryTypeManager})));
}
protected void addWorkspace( String workspaceName,
@@ -937,13 +933,6 @@ public class JcrRepository implements Repository {
}
/**
- * @return jcrSystemObservers
- */
- Collection getSystemObservers() {
- return jcrSystemObservers;
- }
-
- /**
* Get the name of the source that we want to observe.
*
* @return the name of the source that should be observed; never null
@@ -1726,11 +1715,16 @@ public class JcrRepository implements Repository {
*/
class SystemChangeObserver implements Observer {
+ /**
+ * Immutable collection of objects observing changes to the system graph
+ */
+ private final Collection jcrSystemObservers;
private final String processId;
private final String systemSourceName;
private final String systemWorkspaceName;
- SystemChangeObserver() {
+ SystemChangeObserver( Collection jcrSystemObservers ) {
+ this.jcrSystemObservers = Collections.unmodifiableCollection(jcrSystemObservers);
processId = getExecutionContext().getProcessId();
systemSourceName = getSystemSourceName();
systemWorkspaceName = getSystemWorkspaceName();
@@ -1742,9 +1736,21 @@ public class JcrRepository implements Repository {
@Override
public void notify( Changes changes ) {
-
// Don't process changes from outside the system graph
- if (!changes.getSourceName().equals(systemSourceName)) return;
+ if (!changes.getSourceName().equals(systemSourceName)) {
+ /*
+ * It's permissable for the system source to be the same as the source for the workspaces.
+ * In that case, the RepositoryObservationManager would have already translated the system
+ * source name into the observeable source name (from getObservableSourceName()), obscuring
+ * the actual source.
+ *
+ * So if the change source name doesn't equal the system source name BUT the system source name
+ * is the same as the repository (read: workspace) source name, don't give up yet. The difference
+ * may be due to RepositoryObservationManager. Rely on the systemWorkspaceName check below to
+ * be sure.
+ */
+ if (!systemSourceName.equals(getRepositorySourceName())) return;
+ }
// Don't process changes from this repository
if (changes.getProcessId().equals(processId)) return;
@@ -1758,7 +1764,7 @@ public class JcrRepository implements Repository {
Path changedPath = change.changedLocation().getPath();
if (changedPath == null) continue;
- for (JcrSystemObserver jcrSystemObserver : getSystemObservers()) {
+ for (JcrSystemObserver jcrSystemObserver : jcrSystemObservers) {
if (changedPath.isAtOrBelow(jcrSystemObserver.getObservedPath())) {
systemChanges.put(jcrSystemObserver, change);
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java (working copy)
@@ -118,8 +118,7 @@ class RepositoryLockManager implements JcrSystemObserver {
for (Location lockLocation : locksGraph.getRoot().getChildren()) {
Node lockNode = locksGraph.getNode(lockLocation);
- Boolean isSessionScoped = booleanFactory.create(lockNode.getProperty(ModeShapeLexicon.IS_SESSION_SCOPED)
- .getFirstValue());
+ Boolean isSessionScoped = booleanFactory.create(lockNode.getProperty(ModeShapeLexicon.IS_SESSION_SCOPED).getFirstValue());
if (!isSessionScoped) continue;
String lockingSession = stringFactory.create(lockNode.getProperty(ModeShapeLexicon.LOCKING_SESSION).getFirstValue());
@@ -128,8 +127,7 @@ class RepositoryLockManager implements JcrSystemObserver {
if (activeSessionIds.contains(lockingSession)) {
systemGraph.set(ModeShapeLexicon.EXPIRATION_DATE).on(lockLocation).to(newExpirationDate);
} else {
- DateTime expirationDate = dateFactory.create(lockNode.getProperty(ModeShapeLexicon.EXPIRATION_DATE)
- .getFirstValue());
+ DateTime expirationDate = dateFactory.create(lockNode.getProperty(ModeShapeLexicon.EXPIRATION_DATE).getFirstValue());
// Destroy expired locks (if it was still held by an active session, it would have been extended by now)
if (expirationDate.isBefore(now)) {
String workspaceName = stringFactory.create(lockNode.getProperty(ModeShapeLexicon.WORKSPACE).getFirstValue());
@@ -170,14 +168,11 @@ class RepositoryLockManager implements JcrSystemObserver {
UUID lockedNodeUuid = UUID.fromString(string(rawUuid));
assert lockedNodeUuid != null;
- String workspaceName = change.changedWorkspace();
- WorkspaceLockManager workspaceManager = getLockManager(workspaceName);
- assert workspaceManager != null;
-
switch (change.getType()) {
case CREATE_NODE:
CreateNodeRequest create = (CreateNodeRequest)change;
+ Property workspaceNameProp = null;
Property lockOwnerProp = null;
Property lockUuidProp = null;
Property isDeepProp = null;
@@ -192,19 +187,33 @@ class RepositoryLockManager implements JcrSystemObserver {
isSessionScopedProp = prop;
} else if (JcrLexicon.UUID.equals(prop.getName())) {
isSessionScopedProp = prop;
+ } else if (ModeShapeLexicon.WORKSPACE_NAME.equals(prop.getName())) {
+ workspaceNameProp = prop;
}
}
String lockOwner = firstString(lockOwnerProp);
+ String workspaceName = firstString(workspaceNameProp);
UUID lockUuid = firstUuid(lockUuidProp);
boolean isDeep = firstBoolean(isDeepProp);
boolean isSessionScoped = firstBoolean(isSessionScopedProp);
+ WorkspaceLockManager workspaceManager = getLockManager(workspaceName);
+ assert workspaceManager != null;
+
workspaceManager.lockNodeInternally(lockOwner, lockUuid, lockedNodeUuid, isDeep, isSessionScoped);
break;
case DELETE_BRANCH:
- boolean success = workspaceManager.unlockNodeInternally(lockedNodeUuid);
+
+
+ boolean success = false;
+ for (WorkspaceLockManager workspaceLockManager : lockManagers.values()) {
+ if (workspaceLockManager.lockFor(lockedNodeUuid) != null) {
+ success |= workspaceLockManager.unlockNodeInternally(lockedNodeUuid);
+ break;
+ }
+ }
assert success : "No internal lock existed for node " + lockedNodeUuid.toString();
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (revision 2072)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryNodeTypeManager.java (working copy)
@@ -48,14 +48,17 @@ import javax.jcr.query.InvalidQueryException;
import javax.jcr.version.OnParentVersionAction;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
+import org.modeshape.common.collection.Problems;
import org.modeshape.common.i18n.I18n;
import org.modeshape.common.text.TextEncoder;
import org.modeshape.common.text.XmlNameEncoder;
import org.modeshape.common.util.CheckArg;
+import org.modeshape.common.util.Logger;
import org.modeshape.graph.ExecutionContext;
import org.modeshape.graph.Graph;
import org.modeshape.graph.Location;
import org.modeshape.graph.Subgraph;
+import org.modeshape.graph.observe.Changes;
import org.modeshape.graph.property.Name;
import org.modeshape.graph.property.NameFactory;
import org.modeshape.graph.property.Path;
@@ -69,6 +72,7 @@ import org.modeshape.graph.query.model.TypeSystem;
import org.modeshape.graph.query.parse.QueryParser;
import org.modeshape.graph.query.parse.SqlQueryParser;
import org.modeshape.graph.query.validate.Schemata;
+import org.modeshape.graph.request.ChangeRequest;
import org.modeshape.jcr.nodetype.InvalidNodeTypeDefinitionException;
import org.modeshape.jcr.nodetype.NodeTypeExistsException;
@@ -85,13 +89,15 @@ import org.modeshape.jcr.nodetype.NodeTypeExistsException;
*
*/
@ThreadSafe
-class RepositoryNodeTypeManager {
+class RepositoryNodeTypeManager implements JcrSystemObserver {
+ private static final Logger LOGGER = Logger.getLogger(RepositoryNodeTypeManager.class);
private static final TextEncoder NAME_ENCODER = new XmlNameEncoder();
private final JcrRepository repository;
private final QueryParser queryParser;
private final ExecutionContext context;
+ private final Path nodeTypesPath;
@GuardedBy( "nodeTypeManagerLock" )
private final Map nodeTypes;
@@ -130,8 +136,10 @@ class RepositoryNodeTypeManager {
}
RepositoryNodeTypeManager( JcrRepository repository,
+ Path nodeTypesPath,
boolean includeColumnsForInheritedProperties ) {
this.repository = repository;
+ this.nodeTypesPath = nodeTypesPath;
this.context = repository.getExecutionContext();
this.includeColumnsForInheritedProperties = includeColumnsForInheritedProperties;
this.propertyFactory = context.getPropertyFactory();
@@ -143,6 +151,14 @@ class RepositoryNodeTypeManager {
nodeTypes = new HashMap(50);
queryParser = new SqlQueryParser();
+ if (nodeTypesPath != null) {
+ Graph systemGraph = repository.createSystemGraph(context);
+ try {
+ systemGraph.getNodeAt(nodeTypesPath);
+ } catch (PathNotFoundException pnfe) {
+ systemGraph.create(nodeTypesPath).with(JcrLexicon.PRIMARY_TYPE, ModeShapeLexicon.NODE_TYPES).and();
+ }
+ }
}
/**
@@ -1139,7 +1155,7 @@ class RepositoryNodeTypeManager {
propsList.add(propertyFactory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, nodeType.hasOrderableChildNodes()));
propsList.add(propertyFactory.create(JcrLexicon.SUPERTYPES, supertypeNames));
- batch.create(nodeTypePath).with(propsList).and();
+ batch.create(nodeTypePath).with(propsList).orReplace().and();
PropertyDefinition[] propertyDefs = nodeType.getDeclaredPropertyDefinitions();
for (int i = 0; i < propertyDefs.length; i++) {
@@ -1192,7 +1208,8 @@ class RepositoryNodeTypeManager {
propsList.add(propertyFactory.create(JcrLexicon.PROTECTED, jcrPropDef.isProtected()));
propsList.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION,
OnParentVersionAction.nameFromValue(jcrPropDef.getOnParentVersion())));
- propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_TYPE, PropertyType.nameFromValue(jcrPropDef.getRequiredType())));
+ propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_TYPE,
+ PropertyType.nameFromValue(jcrPropDef.getRequiredType()).toUpperCase()));
Value[] defaultValues = jcrPropDef.getDefaultValues();
if (defaultValues.length > 0) {
@@ -1211,7 +1228,7 @@ class RepositoryNodeTypeManager {
String[] valueConstraints = jcrPropDef.getValueConstraints();
if (valueConstraints.length > 0) {
- propsList.add(propertyFactory.create(JcrLexicon.DEFAULT_VALUES, (Object[])valueConstraints));
+ propsList.add(propertyFactory.create(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints));
}
batch.create(propDefPath).with(propsList).and();
}
@@ -1254,7 +1271,7 @@ class RepositoryNodeTypeManager {
propsList.add(propertyFactory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, jcrNodeDef.getDefaultPrimaryType().getName()));
}
- propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, jcrNodeDef.requiredPrimaryTypeNameSet()));
+ propsList.add(propertyFactory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])jcrNodeDef.requiredPrimaryTypeNames()));
propsList.add(propertyFactory.create(JcrLexicon.SAME_NAME_SIBLINGS, jcrNodeDef.allowsSameNameSiblings()));
propsList.add(propertyFactory.create(JcrLexicon.ON_PARENT_VERSION,
OnParentVersionAction.nameFromValue(jcrNodeDef.getOnParentVersion())));
@@ -1347,6 +1364,17 @@ class RepositoryNodeTypeManager {
}
this.nodeTypes.keySet().removeAll(nodeTypeNames);
+
+ if (nodeTypesPath != null) {
+ Graph.Batch batch = repository.createSystemGraph(context).batch();
+
+ for (Name nodeTypeName : nodeTypeNames) {
+ Path nodeTypePath = pathFactory.create(nodeTypesPath, nodeTypeName);
+ batch.delete(nodeTypePath).and();
+ }
+
+ batch.execute();
+ }
this.schemata = null;
} finally {
@@ -1546,6 +1574,9 @@ class RepositoryNodeTypeManager {
}
}
+ Graph.Batch batch = null;
+ if (nodeTypesPath != null) batch = repository.createSystemGraph(context).batch();
+
for (JcrNodeType nodeType : typesPendingRegistration) {
/*
* See comment in constructor. Using a ConcurrentHashMap seems to be to weak of a
@@ -1561,15 +1592,18 @@ class RepositoryNodeTypeManager {
propertyDefinitions.put(propertyDefinition.getId(), propertyDefinition);
}
- // projectNodeTypeOnto(nodeType, parentOfTypeNodes, batch);
+ if (nodeTypesPath != null) projectNodeTypeOnto(nodeType, nodeTypesPath, batch);
}
// Throw away the schemata, since the node types have changed ...
this.schemata = null;
+ if (nodeTypesPath != null) {
+ assert batch != null;
+ batch.execute();
+ }
} finally {
nodeTypeManagerLock.writeLock().unlock();
}
- // batch.execute();
return typesPendingRegistration;
}
@@ -1739,16 +1773,16 @@ class RepositoryNodeTypeManager {
}
/**
- * Finds the named type in the given list of types pending registration if it exists, else returns the type definition from
- * the repository
+ * Finds the named type in the given collection of types pending registration if it exists, else returns the type definition
+ * from the repository
*
* @param typeName the name of the type to retrieve
- * @param pendingList a list of types that have passed validation but have not yet been committed to the repository
- * @return the node type with the given name from {@code pendingList} if it exists in the list or from the {@link #nodeTypes
- * registered types} if it exists there; may be null
+ * @param pendingList a collection of types that have passed validation but have not yet been committed to the repository
+ * @return the node type with the given name from {@code pendingList} if it exists in the collection or from the
+ * {@link #nodeTypes registered types} if it exists there; may be null
*/
private JcrNodeType findTypeInMapOrList( Name typeName,
- List pendingList ) {
+ Collection pendingList ) {
for (JcrNodeType pendingNodeType : pendingList) {
if (pendingNodeType.getInternalName().equals(typeName)) {
return pendingNodeType;
@@ -1770,7 +1804,7 @@ class RepositoryNodeTypeManager {
* already-registered node type or a node type that is pending registration
*/
private List supertypesFor( NodeTypeDefinition nodeType,
- List pendingTypes ) throws RepositoryException {
+ Collection pendingTypes ) throws RepositoryException {
assert nodeType != null;
List supertypes = new LinkedList();
@@ -2204,4 +2238,86 @@ class RepositoryNodeTypeManager {
}
}
+ @Override
+ public Path getObservedPath() {
+ return this.nodeTypesPath;
+ }
+
+ @Override
+ public void notify( Changes changes ) {
+ boolean needsReload = false;
+
+ for (ChangeRequest change : changes.getChangeRequests()) {
+ assert change.changedLocation().hasPath();
+
+ Path changedPath = change.changedLocation().getPath();
+ if (changedPath.equals(nodeTypesPath)) {
+ // nothing to do with the "/jcr:system/jcr:nodeTypes" node ...
+ continue;
+ }
+ assert nodeTypesPath.isAncestorOf(changedPath);
+
+ switch (change.getType()) {
+ case CREATE_NODE:
+ case DELETE_BRANCH:
+ needsReload = true;
+
+ break;
+ default:
+ assert false : "Unexpected change request: " + change;
+ }
+ }
+
+ if (!needsReload) return;
+
+ this.nodeTypeManagerLock.writeLock().lock();
+ try {
+ GraphNodeTypeReader reader = new GraphNodeTypeReader(this.context);
+ Graph systemGraph = repository.createSystemGraph(this.context);
+
+ reader.read(systemGraph, nodeTypesPath, null);
+
+ Problems readerProblems = reader.getProblems();
+ if (readerProblems.hasProblems()) {
+ if (readerProblems.hasErrors()) {
+ LOGGER.error(JcrI18n.errorReadingNodeTypesFromRemote, reader.getProblems());
+ return;
+ }
+
+ LOGGER.warn(JcrI18n.problemReadingNodeTypesFromRemote, reader.getProblems());
+ }
+
+ Map newNodeTypeMap = new HashMap();
+ try {
+ for (NodeTypeDefinition nodeTypeDefn : reader.getNodeTypeDefinitions()) {
+ List supertypes = supertypesFor(nodeTypeDefn, newNodeTypeMap.values());
+ JcrNodeType nodeType = nodeTypeFrom(nodeTypeDefn, supertypes);
+
+ newNodeTypeMap.put(nodeType.getInternalName(), nodeType);
+ }
+ } catch (Throwable re) {
+ LOGGER.error(JcrI18n.errorSynchronizingNodeTypes, re);
+ }
+
+ this.nodeTypes.clear();
+ this.nodeTypes.putAll(newNodeTypeMap);
+
+ assert this.nodeTypes.get(ModeShapeLexicon.ROOT) != null;
+
+ for (JcrSession activeSession : repository.activeSessions()) {
+ JcrWorkspace workspace = activeSession.workspace();
+ if (workspace == null) continue;
+
+ JcrNodeTypeManager nodeTypeManager = workspace.nodeTypeManager();
+ if (nodeTypeManager == null) continue;
+
+ nodeTypeManager.signalExternalNodeTypeChanges();
+ }
+
+ } finally {
+ this.schemata = null;
+ this.nodeTypeManagerLock.writeLock().unlock();
+ }
+
+ }
}
Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties
===================================================================
--- modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (revision 2072)
+++ modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (working copy)
@@ -187,6 +187,10 @@ cannotUseMixinTypeAsPrimaryType = This operation requires a primary type, but "{
primaryTypeCannotBeAbstract = The prrimary type of a node cannot be abstract, like "{0}"
setPrimaryTypeNotSupported = ModeShape does not currently allow modifying the primary type of a node
+errorReadingNodeTypesFromRemote = Node types changed due to remote update. Node types are likely to be different across nodes in the cluster. Encountered following errors reading node types from graph: {0}
+problemReadingNodeTypesFromRemote = Node types changed due to remote update. Encountered following problems reading node types from graph: {0}
+errorSynchronizingNodeTypes = Node types changed due to remote update. Could not rebuild node type map. Node types are likely to be different across nodes in the cluster.
+
# Lock messages
nodeNotLockable = The node at '{0}' is not lockable. Add the 'mix:lockable' mixin type to make it lockable.
cannotRemoveLockToken = The lock token '{0}' is a session-scoped lock
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (working copy)
@@ -83,7 +83,7 @@ public abstract class AbstractJcrTest {
repoLockManager = mock(RepositoryLockManager.class);
when(repository.getRepositoryLockManager()).thenReturn(repoLockManager);
- rntm = new RepositoryNodeTypeManager(repository, true);
+ rntm = new RepositoryNodeTypeManager(repository, null, true);
try {
CndNodeTypeReader cndReader = new CndNodeTypeReader(context);
cndReader.readBuiltInTypes();
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractSessionTest.java (working copy)
@@ -145,7 +145,7 @@ public abstract class AbstractSessionTest {
when(repository.getRepositoryLockManager()).thenReturn(repoLockManager);
// Stub out the repository, since we only need a few methods ...
- repoTypeManager = new RepositoryNodeTypeManager(repository, true);
+ repoTypeManager = new RepositoryNodeTypeManager(repository, null, true);
when(repository.getRepositoryTypeManager()).thenReturn(repoTypeManager);
try {
@@ -194,7 +194,6 @@ public abstract class AbstractSessionTest {
registry = session.getExecutionContext().getNamespaceRegistry();
}
- @SuppressWarnings( "unused" )
protected List getTestTypes() throws ConstraintViolationException {
return Collections.emptyList();
}
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/CndNodeTypeRegistrationTest.java (working copy)
@@ -62,7 +62,7 @@ public class CndNodeTypeRegistrationTest {
when(repository.getExecutionContext()).thenReturn(context);
- repoTypeManager = new RepositoryNodeTypeManager(repository, true);
+ repoTypeManager = new RepositoryNodeTypeManager(repository, null, true);
try {
CndNodeTypeReader cndReader = new CndNodeTypeReader(context);
cndReader.readBuiltInTypes();
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JackrabbitXmlNodeTypeRegistrationTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/JackrabbitXmlNodeTypeRegistrationTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/JackrabbitXmlNodeTypeRegistrationTest.java (working copy)
@@ -67,7 +67,7 @@ public class JackrabbitXmlNodeTypeRegistrationTest {
when(repository.getExecutionContext()).thenReturn(context);
- repoTypeManager = new RepositoryNodeTypeManager(repository, true);
+ repoTypeManager = new RepositoryNodeTypeManager(repository, null, true);
try {
CndNodeTypeReader cndFactory = new CndNodeTypeReader(context);
cndFactory.readBuiltInTypes();
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/TypeRegistrationTest.java (working copy)
@@ -32,9 +32,7 @@ import java.util.Arrays;
import java.util.List;
import javax.jcr.PropertyType;
import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeTypeDefinition;
-import javax.jcr.nodetype.PropertyDefinition;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -43,10 +41,8 @@ import org.modeshape.graph.property.Name;
import org.modeshape.graph.property.NameFactory;
import org.modeshape.graph.property.NamespaceRegistry;
import org.modeshape.jcr.nodetype.InvalidNodeTypeDefinitionException;
-import org.modeshape.jcr.nodetype.NodeDefinitionTemplate;
import org.modeshape.jcr.nodetype.NodeTypeExistsException;
import org.modeshape.jcr.nodetype.NodeTypeTemplate;
-import org.modeshape.jcr.nodetype.PropertyDefinitionTemplate;
public class TypeRegistrationTest extends AbstractSessionTest {
@@ -921,113 +917,6 @@ public class TypeRegistrationTest extends AbstractSessionTest {
assertThat(nodeType.nodeTypeManager(), is(notNullValue()));
}
- assertThat(nodeType, is(notNullValue()));
- assertThat(nodeType.getName(), is(template.getName()));
- assertThat(nodeType.getDeclaredSupertypes().length, is(template.getDeclaredSupertypeNames().length));
- for (int i = 0; i < template.getDeclaredSupertypeNames().length; i++) {
- assertThat(template.getDeclaredSupertypeNames()[i], is(nodeType.getDeclaredSupertypes()[i].getName()));
- }
- assertThat(template.isMixin(), is(nodeType.isMixin()));
- assertThat(template.hasOrderableChildNodes(), is(nodeType.hasOrderableChildNodes()));
-
- PropertyDefinition[] propertyDefs = nodeType.getDeclaredPropertyDefinitions();
- List propertyTemplates = template.getPropertyDefinitionTemplates();
-
- assertThat(propertyDefs.length, is(propertyTemplates.size()));
- for (PropertyDefinitionTemplate pt : propertyTemplates) {
- JcrPropertyDefinitionTemplate propertyTemplate = (JcrPropertyDefinitionTemplate)pt;
-
- PropertyDefinition matchingDefinition = null;
- for (int i = 0; i < propertyDefs.length; i++) {
- PropertyDefinition pd = propertyDefs[i];
-
- String ptName = propertyTemplate.getName() == null ? JcrNodeType.RESIDUAL_ITEM_NAME : propertyTemplate.getName();
- if (pd.getName().equals(ptName) && pd.getRequiredType() == propertyTemplate.getRequiredType()
- && pd.isMultiple() == propertyTemplate.isMultiple()) {
- matchingDefinition = pd;
- break;
- }
- }
-
- comparePropertyTemplateToPropertyDefinition(propertyTemplate, (JcrPropertyDefinition)matchingDefinition);
- }
-
- NodeDefinition[] childNodeDefs = nodeType.getDeclaredChildNodeDefinitions();
- List childNodeTemplates = template.getNodeDefinitionTemplates();
-
- assertThat(childNodeDefs.length, is(childNodeTemplates.size()));
- for (NodeDefinitionTemplate nt : childNodeTemplates) {
- JcrNodeDefinitionTemplate childNodeTemplate = (JcrNodeDefinitionTemplate)nt;
-
- NodeDefinition matchingDefinition = null;
- for (int i = 0; i < childNodeDefs.length; i++) {
- NodeDefinition nd = childNodeDefs[i];
-
- String ntName = childNodeTemplate.getName() == null ? JcrNodeType.RESIDUAL_ITEM_NAME : childNodeTemplate.getName();
- if (nd.getName().equals(ntName) && nd.allowsSameNameSiblings() == childNodeTemplate.allowsSameNameSiblings()) {
-
- if (nd.getRequiredPrimaryTypes().length != childNodeTemplate.getRequiredPrimaryTypeNames().length) continue;
-
- boolean matchesOnRequiredTypes = true;
- for (int j = 0; j < nd.getRequiredPrimaryTypes().length; j++) {
- String ndName = nd.getRequiredPrimaryTypes()[j].getName();
- String tempName = childNodeTemplate.getRequiredPrimaryTypeNames()[j];
- if (!ndName.equals(tempName)) {
- matchesOnRequiredTypes = false;
- break;
- }
- }
-
- if (matchesOnRequiredTypes) {
- matchingDefinition = nd;
- break;
- }
- }
- }
-
- compareNodeTemplateToNodeDefinition(childNodeTemplate, (JcrNodeDefinition)matchingDefinition);
- }
-
- }
-
- private void comparePropertyTemplateToPropertyDefinition( JcrPropertyDefinitionTemplate template,
- JcrPropertyDefinition definition ) {
-
- assertThat(definition, is(notNullValue()));
- assertThat(definition.getDeclaringNodeType(), is(notNullValue()));
- // Had to match on name to even get to the definition
- // assertThat(template.getName(), is(definition.getName()));
-
- assertThat(emptyIfNull(template.getValueConstraints()), is(definition.getValueConstraints()));
- assertThat(template.getOnParentVersion(), is(definition.getOnParentVersion()));
- assertThat(template.getRequiredType(), is(definition.getRequiredType()));
- assertThat(template.isAutoCreated(), is(definition.isAutoCreated()));
- assertThat(template.isMandatory(), is(definition.isMandatory()));
- assertThat(template.isMultiple(), is(definition.isMultiple()));
- assertThat(template.isProtected(), is(definition.isProtected()));
- }
-
- private void compareNodeTemplateToNodeDefinition( JcrNodeDefinitionTemplate template,
- JcrNodeDefinition definition ) {
- assertThat(definition, is(notNullValue()));
- assertThat(definition.getDeclaringNodeType(), is(notNullValue()));
- // Had to match on name to even get to the definition
- // assertThat(template.getName(), is(definition.getName()));
-
- assertThat(template.getOnParentVersion(), is(definition.getOnParentVersion()));
- assertThat(template.isAutoCreated(), is(definition.isAutoCreated()));
- assertThat(template.isMandatory(), is(definition.isMandatory()));
- assertThat(template.isProtected(), is(definition.isProtected()));
-
- assertThat(template.getDefaultPrimaryType(), is(definition.getDefaultPrimaryType()));
- assertThat(template.allowsSameNameSiblings(), is(definition.allowsSameNameSiblings()));
-
- // assertThat(template.getRequiredPrimaryTypeNames(), is(definition.getRequiredPrimaryTypeNames()));
-
- }
-
- private String[] emptyIfNull( String[] incoming ) {
- if (incoming != null) return incoming;
- return new String[0];
+ NodeTypeAssertion.compareTemplateToNodeType(template, nodeType);
}
}
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/WorkspaceLockManagerTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/WorkspaceLockManagerTest.java (revision 2072)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/WorkspaceLockManagerTest.java (working copy)
@@ -101,7 +101,9 @@ public class WorkspaceLockManagerTest {
});
// Stub out the repository, since we only need a few methods ...
- repoTypeManager = new RepositoryNodeTypeManager(repository, true);
+ Path nodeTypesPath = context.getValueFactories().getPathFactory().createAbsolutePath(JcrLexicon.SYSTEM,
+ JcrLexicon.NODE_TYPES);
+ repoTypeManager = new RepositoryNodeTypeManager(repository, nodeTypesPath, true);
when(repository.getRepositoryTypeManager()).thenReturn(repoTypeManager);
@@ -153,8 +155,6 @@ public class WorkspaceLockManagerTest {
when(session.getExecutionContext()).thenReturn(context);
workspaceLockManager.lockNodeInRepository(session, validUuid, lockOwner, isDeep);
- // At the moment, a VerifyWorkspaceRequest is being executed when the graph is created.
- executedRequests.poll();
assertNextRequestIsLock(validLocation, LockScope.SELF_ONLY, 0);
}
@@ -163,8 +163,6 @@ public class WorkspaceLockManagerTest {
ModeShapeLock lock = workspaceLockManager.createLock("testOwner", UUID.randomUUID(), validUuid, false, false);
workspaceLockManager.unlockNodeInRepository(context, lock);
- // At the moment, a VerifyWorkspaceRequest is being executed when the graph is created.
- executedRequests.poll();
assertNextRequestIsUnlock(validLocation);
}
Index: modeshape-jcr/src/test/resources/tck/default/configRepository.xml
===================================================================
--- modeshape-jcr/src/test/resources/tck/default/configRepository.xml (revision 2072)
+++ modeshape-jcr/src/test/resources/tck/default/configRepository.xml (working copy)
@@ -72,7 +72,7 @@
-
+