Index: src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java	(revision 532302)
+++ src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java	(working copy)
@@ -16,17 +16,30 @@
  */
 package org.apache.jackrabbit.core.cluster;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.config.ClusterConfig;
 import org.apache.jackrabbit.core.config.ConfigurationException;
 import org.apache.jackrabbit.core.config.JournalConfig;
-import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.journal.FileRevision;
 import org.apache.jackrabbit.core.journal.Journal;
+import org.apache.jackrabbit.core.journal.JournalException;
+import org.apache.jackrabbit.core.journal.Record;
 import org.apache.jackrabbit.core.journal.RecordConsumer;
-import org.apache.jackrabbit.core.journal.Record;
-import org.apache.jackrabbit.core.journal.JournalException;
-import org.apache.jackrabbit.core.journal.FileRevision;
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
 import org.apache.jackrabbit.core.observation.EventState;
@@ -35,23 +48,13 @@
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.name.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import EDU.oswego.cs.dl.util.concurrent.Mutex;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.HashSet;
-import java.io.File;
-
 /**
  * Default clustered node implementation.
  */
@@ -426,6 +429,70 @@
     /**
      * {@inheritDoc}
      */
+    public void reregistered(NodeTypeDef ntDef) {
+        if (status != STARTED) {
+            log.info("not started: nodetype operation ignored.");
+            return;
+        }
+        Record record = null;
+        boolean succeeded = false;
+
+        try {
+            record = journal.getProducer(PRODUCER_ID).append();
+            record.writeString(null);
+            write(record, ntDef);
+            record.writeChar('\0');
+            record.update();
+            setRevision(record.getRevision());
+            succeeded = true;
+        } catch (JournalException e) {
+            String msg = "Unable to create log entry: " + e.getMessage();
+            log.error(msg);
+        } catch (Throwable e) {
+            String msg = "Unexpected error while creating log entry.";
+            log.error(msg, e);
+        } finally {
+            if (!succeeded && record != null) {
+                record.cancelUpdate();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregistered(Collection qnames) {
+        if (status != STARTED) {
+            log.info("not started: nodetype operation ignored.");
+            return;
+        }
+        Record record = null;
+        boolean succeeded = false;
+
+        try {
+            record = journal.getProducer(PRODUCER_ID).append();
+            record.writeString(null);
+            write(record, qnames);
+            record.writeChar('\0');
+            record.update();
+            setRevision(record.getRevision());
+            succeeded = true;
+        } catch (JournalException e) {
+            String msg = "Unable to create log entry: " + e.getMessage();
+            log.error(msg);
+        } catch (Throwable e) {
+            String msg = "Unexpected error while creating log entry.";
+            log.error(msg, e);
+        } finally {
+            if (!succeeded && record != null) {
+                record.cancelUpdate();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void setListener(NodeTypeEventListener listener) {
         nodeTypeListener = listener;
     }
@@ -800,6 +867,50 @@
     }
 
     /**
+     * Process one or more node type re-registrations.
+     *
+     * @param ntDefs node type definition
+     */
+    private void process(NodeTypeDef ntDef) {
+        if (nodeTypeListener == null) {
+            String msg = "NodeType listener unavailable.";
+            log.error(msg);
+            return;
+        }
+        try {
+            nodeTypeListener.externalReregistered(ntDef);
+        } catch (InvalidNodeTypeDefException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        } catch (RepositoryException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        }
+    }
+
+    /**
+     * Process one or more node type unregistrations.
+     *
+     * @param qnames names of unregistered node types
+     */
+    private void processNames(Collection qnames) {
+        if (nodeTypeListener == null) {
+            String msg = "NodeType listener unavailable.";
+            log.error(msg);
+            return;
+        }
+        try {
+            nodeTypeListener.externalUnregistered(qnames);
+        } catch (NoSuchNodeTypeException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        } catch (RepositoryException e) {
+            String msg = "Unable to deliver node type operation: " + e.getMessage();
+            log.error(msg);
+        }
+    }
+
+    /**
      * Invoked when a record ends.
      */
     private void end() {
@@ -922,6 +1033,15 @@
                         ntDefs.add(record.readNodeTypeDef());
                     }
                     process(ntDefs);
+                } else if (c == 'R') {
+                    process(record.readNodeTypeDef());
+                } else if (c == 'U') {
+                    int size = record.readInt();
+                    HashSet qnames = new HashSet();
+                    for (int i = 0; i < size; i++) {
+                        qnames.add(record.readQName());
+                    }
+                    processNames(qnames);
                 } else {
                     throw new IllegalArgumentException("Unknown entry type: " + c);
                 }
@@ -1072,6 +1192,25 @@
         }
     }
 
+    private static void writeNames(Record record, Collection qnames)
+        throws JournalException {
+
+        record.writeChar('U');
+        record.writeInt(qnames.size());
+
+        Iterator iter = qnames.iterator();
+        while (iter.hasNext()) {
+            record.writeQName((QName) iter.next());
+        }
+    }
+
+    private static void write(Record record, NodeTypeDef ntDef)
+        throws JournalException {
+
+        record.writeChar('R');
+        record.writeNodeTypeDef(ntDef);
+    }
+
     private static void write(Record record, PropertyOperation operation)
             throws JournalException {
 
Index: src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java	(revision 532302)
+++ src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventChannel.java	(working copy)
@@ -18,6 +18,8 @@
 
 import java.util.Collection;
 
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+
 /**
  * Event channel used to transmit nodetype registry operations.
  */
@@ -31,6 +33,20 @@
     public void registered(Collection ntDefs);
 
     /**
+     * Called when a node types has been re-registered.
+     *
+     * @param ntDefs collection of node type definitions
+     */
+    public void reregistered(NodeTypeDef ntDef);
+
+    /**
+     * Called when one or more node types have been unregistered.
+     *
+     * @param qnames collection of node type qnames
+     */
+    public void unregistered(Collection qnames);
+
+    /**
      * Set listener that will receive information about incoming, external node type events.
      *
      * @param listener node type event listener
Index: src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java	(revision 532302)
+++ src/main/java/org/apache/jackrabbit/core/cluster/NodeTypeEventListener.java	(working copy)
@@ -16,11 +16,14 @@
  */
 package org.apache.jackrabbit.core.cluster;
 
-import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import java.util.Collection;
 
 import javax.jcr.RepositoryException;
-import java.util.Collection;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 
+import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+
 /**
  * Interface used to receive information about incoming, external node type registry events.
  */
@@ -35,4 +38,25 @@
      */
     public void externalRegistered(Collection ntDefs)
             throws RepositoryException, InvalidNodeTypeDefException;
+
+    /**
+     * Called when a node type has been externally re-registered.
+     *
+     * @param ntDef node type definition
+     * @throws RepositoryException if an error occurs
+     * @throws NoSuchNodeTypeException if the node type had not yet been registered
+     * @throws InvalidNodeTypeDefException if the node type definition is invalid
+     */
+    public void externalReregistered(NodeTypeDef ntDef)
+        throws NoSuchNodeTypeException, InvalidNodeTypeDefException, RepositoryException;
+
+    /**
+     * Called when one or more node types have been externally unregistered.
+     *
+     * @param ntNames node type qnames
+     * @throws RepositoryException if an error occurs
+     * @throws NoSuchNodeTypeException if a node type is already unregistered
+     */
+    public void externalUnregistered(Collection ntNames)
+        throws RepositoryException, NoSuchNodeTypeException;
 }
Index: src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	(revision 532302)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	(working copy)
@@ -16,19 +16,6 @@
  */
 package org.apache.jackrabbit.core.nodetype;
 
-import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
-import org.apache.commons.collections.map.ReferenceMap;
-import org.apache.jackrabbit.core.cluster.NodeTypeEventChannel;
-import org.apache.jackrabbit.core.cluster.NodeTypeEventListener;
-import org.apache.jackrabbit.core.fs.FileSystem;
-import org.apache.jackrabbit.core.fs.FileSystemException;
-import org.apache.jackrabbit.core.fs.FileSystemResource;
-import org.apache.jackrabbit.core.util.Dumpable;
-import org.apache.jackrabbit.core.value.InternalValue;
-import org.apache.jackrabbit.name.QName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -49,6 +36,20 @@
 import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.version.OnParentVersionAction;
 
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.core.cluster.NodeTypeEventChannel;
+import org.apache.jackrabbit.core.cluster.NodeTypeEventListener;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemException;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.util.Dumpable;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.name.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
+
 /**
  * A <code>NodeTypeRegistry</code> ...
  */
@@ -168,7 +169,7 @@
      * @throws RepositoryException if a repository error occurs.
      */
     public synchronized EffectiveNodeType registerNodeType(NodeTypeDef ntd)
-            throws InvalidNodeTypeDefException, RepositoryException {
+        throws InvalidNodeTypeDefException, RepositoryException {
         // validate and register new node type definition
         EffectiveNodeType ent = internalRegister(ntd);
 
@@ -176,6 +177,7 @@
         customNTDefs.add(ntd);
         persistCustomNodeTypeDefs(customNTDefs);
 
+        // inform cluster
         if (eventChannel != null) {
             HashSet ntDefs = new HashSet();
             ntDefs.add(ntd);
@@ -200,7 +202,12 @@
      * @throws InvalidNodeTypeDefException if the given node type definition is invalid.
      * @throws RepositoryException if a repository error occurs.
      */
-    public synchronized void registerNodeTypes(Collection ntDefs)
+    public void registerNodeTypes(Collection ntDefs)
+        throws InvalidNodeTypeDefException, RepositoryException {
+        registerNodeTypes(ntDefs, true);
+    }
+
+    private synchronized void registerNodeTypes(Collection ntDefs, boolean informCluster)
             throws InvalidNodeTypeDefException, RepositoryException {
         // validate and register new node type definitions
         internalRegister(ntDefs);
@@ -212,7 +219,7 @@
         persistCustomNodeTypeDefs(customNTDefs);
 
         // inform cluster
-        if (eventChannel != null) {
+        if (eventChannel != null && informCluster) {
             eventChannel.registered(ntDefs);
         }
 
@@ -237,8 +244,13 @@
      * @throws RepositoryException if another error occurs
      * @see #unregisterNodeType(QName)
      */
-    public synchronized void unregisterNodeTypes(Collection ntNames)
-            throws NoSuchNodeTypeException, RepositoryException {
+    public void unregisterNodeTypes(Collection ntNames)
+        throws NoSuchNodeTypeException, RepositoryException {
+        unregisterNodeTypes(ntNames, true);
+    }
+
+    private synchronized void unregisterNodeTypes(Collection ntNames, boolean informCluster)
+        throws NoSuchNodeTypeException, RepositoryException {
         // do some preliminary checks
         for (Iterator iter = ntNames.iterator(); iter.hasNext();) {
             QName ntName = (QName) iter.next();
@@ -273,6 +285,11 @@
         // all preconditions are met, node types can now safely be unregistered
         internalUnregister(ntNames);
 
+        // inform cluster
+        if (eventChannel != null && informCluster) {
+            eventChannel.registered(ntNames);
+        }
+
         // persist removal of node type definitions & notify listeners
         for (Iterator iter = ntNames.iterator(); iter.hasNext();) {
             QName ntName = (QName) iter.next();
@@ -313,7 +330,14 @@
      * @throws InvalidNodeTypeDefException
      * @throws RepositoryException
      */
-    public synchronized EffectiveNodeType reregisterNodeType(NodeTypeDef ntd)
+    public  EffectiveNodeType reregisterNodeType(NodeTypeDef ntd)
+        throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+        RepositoryException {
+
+        return reregisterNodeType(ntd, true);
+    }
+
+    private synchronized EffectiveNodeType reregisterNodeType(NodeTypeDef ntd, boolean informCluster)
             throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
             RepositoryException {
         QName name = ntd.getName();
@@ -358,11 +382,16 @@
             // persist node type definitions
             persistCustomNodeTypeDefs(customNTDefs);
 
+            // inform cluster
+            if (eventChannel != null && informCluster) {
+                eventChannel.reregistered(ntd);
+            }
+
             // notify listeners
             notifyReRegistered(name);
             return entNew;
         }
-        
+
        	String message = "The following nodetype change contains non-trivial changes."
                 + "Up until now only trivial changes are supported."
                 + " (see javadoc for "
@@ -608,21 +637,31 @@
     public void externalRegistered(Collection ntDefs)
             throws RepositoryException, InvalidNodeTypeDefException {
 
-        // validate and register new node type definitions
-        internalRegister(ntDefs);
-        // persist new node type definitions
-        for (Iterator iter = ntDefs.iterator(); iter.hasNext();) {
-            NodeTypeDef ntDef = (NodeTypeDef) iter.next();
-            customNTDefs.add(ntDef);
-        }
-        persistCustomNodeTypeDefs(customNTDefs);
-        // notify listeners
-        for (Iterator iter = ntDefs.iterator(); iter.hasNext();) {
-            NodeTypeDef ntDef = (NodeTypeDef) iter.next();
-            notifyRegistered(ntDef.getName());
-        }
+        // prevent infinite recursive behavior
+        registerNodeTypes(ntDefs, false);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public void externalReregistered(NodeTypeDef ntDef)
+            throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+            RepositoryException {
+
+        // prevent infinite recursive behavior
+        reregisterNodeType(ntDef, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void externalUnregistered(Collection ntNames)
+            throws RepositoryException, NoSuchNodeTypeException {
+
+        // prevent infinite recursive behavior
+        unregisterNodeTypes(ntNames, false);
+    }
+
     //---------------------------------------------------------< overridables >
     /**
      * Protected constructor
@@ -1711,7 +1750,7 @@
         // copy listeners to array to avoid ConcurrentModificationException
         NodeTypeRegistryListener[] la =
                 (NodeTypeRegistryListener[]) listeners.values().toArray(
-                        new NodeTypeRegistryListener[listeners.size()]); 
+                        new NodeTypeRegistryListener[listeners.size()]);
         for (int i = 0; i < la.length; i++) {
             if (la[i] != null) {
                 la[i].nodeTypeRegistered(ntName);
