Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistryTest.java =================================================================== --- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistryTest.java (revision 0) +++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistryTest.java (revision 0) @@ -0,0 +1,117 @@ +package org.apache.jackrabbit.core.nodetype; + +import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader; + +import javax.jcr.InvalidItemStateException; +import javax.jcr.Node; +import javax.jcr.Session; +import javax.jcr.Workspace; +import javax.jcr.nodetype.NodeTypeManager; +import javax.jcr.RepositoryException; + +import java.io.Reader; +import java.io.StringReader; +import java.util.Random; +import java.util.ArrayList; +import java.util.Iterator; + +import junit.framework.TestCase; +import org.apache.jackrabbit.test.AbstractJCRTest; +import org.apache.jackrabbit.test.RepositoryHelper; + + + + +public class NodeTypeRegistryTest extends TestCase { + + public static RepositoryHelper helper = new RepositoryHelper(); + + protected void setUp() throws Exception { + super.setUp(); + } + protected void tearDown() throws Exception { + super.tearDown(); + } + public void testNodeTypeUnregister() throws Exception + { + Session session = helper.getSuperuserSession(); + + // 1. Test type deletion with conflicting content + registerType("\n[nt:testType] > nt:base", session); + + Node node = session.getRootNode().addNode("testNode", "nt:testType"); + + session.save(); + + try + { + unregisterType("nt:testType", session); + fail("Expected a RepositoryException but none thrown"); + }catch(RepositoryException e) + { + ; + } + + // 2. Test type deletion with no conflicting content + node = session.getRootNode().getNode("testNode"); + node.remove(); + + session.save(); + + unregisterType("nt:testType", session); + + //3. Test new node creation with the type removed mid-flight + registerType("\n[nt:testType] > nt:base", session); + node = session.getRootNode().addNode("testNode", "nt:testType"); + unregisterType("nt:testType", session); + try + { + session.save(); + fail("Expected a NoSuchNodeTypeException, but none was thrown"); + } + catch(javax.jcr.nodetype.NoSuchNodeTypeException e) + { + ; + } + } + + + + + // ---------------------------------------------------- +// "\n[nt:testType2] > nt:base" + private static void registerType(String cnd, Session session) + throws Exception { + + Reader r = new StringReader(cnd); + + CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(r, "0"); + NodeTypeDef def = (NodeTypeDef) reader.getNodeTypeDefs().get(0); + + Workspace wsp = session.getWorkspace(); + NodeTypeManager ntMgr = wsp.getNodeTypeManager(); + + // non-JSR 170 - jackrabbit specific + NodeTypeRegistry ntReg = ((NodeTypeManagerImpl) ntMgr) + .getNodeTypeRegistry(); + ntReg.registerNodeType(def); + + } + + private static void unregisterType(String name, Session session) + throws Exception { + NodeTypeImpl type = (NodeTypeImpl) session.getWorkspace() + .getNodeTypeManager().getNodeType(name); + + Workspace wsp = session.getWorkspace(); + NodeTypeManager ntMgr = wsp.getNodeTypeManager(); + + NodeTypeRegistry ntReg = ((NodeTypeManagerImpl) ntMgr) + .getNodeTypeRegistry(); + + ntReg.unregisterNodeType(type.getQName()); + + } + +} Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (revision 504602) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (working copy) @@ -557,7 +557,10 @@ protected NodeTypeRegistry createNodeTypeRegistry(NamespaceRegistry nsReg, FileSystem fs) throws RepositoryException { - return NodeTypeRegistry.create(nsReg, fs); + + NodeTypeRegistry ntRegistry = NodeTypeRegistry.create(nsReg, fs); + ntRegistry.setRepository(this); + return ntRegistry; } /** @@ -853,7 +856,7 @@ * @throws NoSuchWorkspaceException if such a workspace does not exist * @throws RepositoryException if some other error occurs */ - SystemSession getSystemSession(String workspaceName) + public SystemSession getSystemSession(String workspaceName) throws NoSuchWorkspaceException, RepositoryException { // check sanity of this instance sanityCheck(); Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java (revision 504602) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java (working copy) @@ -28,7 +28,11 @@ import org.apache.jackrabbit.name.QName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.name.NoPrefixDeclaredException; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -42,6 +46,9 @@ import java.util.Set; import java.util.Stack; +import javax.jcr.NodeIterator; +import javax.jcr.query.Query; +import javax.jcr.query.QueryResult; import javax.jcr.NamespaceRegistry; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -93,6 +100,8 @@ * used for (de)serializing node type definitions */ private final NamespaceRegistry nsReg; + + private RepositoryImpl repo; /** * Listeners (soft references) @@ -100,7 +109,13 @@ private final Map listeners = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK)); + /** + * No need to synchronize the collection. Should be accessed only from the sychronized getSystemSession() + */ + private final Map systemSessionCache = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); + + /** * Node type event channel. */ private NodeTypeEventChannel eventChannel; @@ -849,13 +864,7 @@ */ protected void checkForConflictingContent(NodeTypeDef ntd) throws RepositoryException { - /** - * collect names of node types that have dependencies on the given - * node type - */ - //Set dependentNTs = getDependentNodeTypes(ntd.getName()); - - throw new RepositoryException("not yet implemented"); + checkForReferencesInContent(ntd.getName()); } /** @@ -884,10 +893,61 @@ * some other reason. */ protected void checkForReferencesInContent(QName nodeTypeName) - throws RepositoryException { - throw new RepositoryException("not yet implemented"); + throws RepositoryException { + + synchronized(repo) + { + SessionImpl sysSession = getSystemSession(repo.getConfig().getDefaultWorkspaceName()); + + String [] workspaces = sysSession.getWorkspace().getAccessibleWorkspaceNames(); + + for(int i=0; i < workspaces.length; ++i) + checkForConflictingContentInWorkspace(nodeTypeName, workspaces[i]); + } } + + private void checkForConflictingContentInWorkspace(QName name, String workspaceName) + throws RepositoryException + { + + SessionImpl session = getSystemSession(workspaceName); + + StringBuffer queryBuff = new StringBuffer("//element(*, "); + try + { + name.toJCRName(session.getNamespaceResolver(), queryBuff); + }catch(NoPrefixDeclaredException e) + { + throw new RepositoryException(e.fillInStackTrace()); + } + queryBuff.append(")"); + + Query query = session.getWorkspace().getQueryManager().createQuery(queryBuff.toString(), Query.XPATH); + + QueryResult result = query.execute(); + NodeIterator iter = result.getNodes(); + if(iter != null && iter.getSize() > 0) + throw new RepositoryException("Conflicting content exists for "+name); + } + private synchronized SessionImpl getSystemSession(String workspaceName) + throws RepositoryException + { + + SessionImpl session; + if(!systemSessionCache.containsKey(workspaceName)) + { + session = repo.getSystemSession(workspaceName); + systemSessionCache.put(workspaceName, session); + } + else + { + session = (SessionImpl)systemSessionCache.get(workspaceName); + } + + return session; + } + //-------------------------------------------------------< implementation > /** * @return the definition of the root node @@ -905,6 +965,11 @@ this.eventChannel = eventChannel; eventChannel.setListener(this); } + + public void setRepository(RepositoryImpl repoImpl) + { + this.repo = repoImpl; + } /** * @param ntName Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (revision 504602) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (working copy) @@ -1052,8 +1052,10 @@ // check state of this instance sanityCheck(); + + // synchronize on this session - synchronized (session) { + synchronized (session.getRepository()) { /** * build list of transient (i.e. new & modified) states that * should be persisted