Index: src/test/java/com/xpn/xwiki/notify/XWikiNotificationManagerTest.java
===================================================================
--- src/test/java/com/xpn/xwiki/notify/XWikiNotificationManagerTest.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/notify/XWikiNotificationManagerTest.java	(revision 0)
@@ -0,0 +1,88 @@
+/*
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ *
+ */
+
+package com.xpn.xwiki.notify;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.doc.XWikiDocument;
+
+import junit.framework.TestCase;
+
+/**
+ * Verify the {@link XWikiNotificationManager}
+ * 
+ * @version $Id: $
+ */
+public class XWikiNotificationManagerTest extends TestCase {
+
+	private XWikiNotificationManager notificationManager;
+
+	protected void setUp() throws Exception {
+		notificationManager = new XWikiNotificationManager();
+		super.setUp();
+	}
+
+	public void testRemoveRuleFromNamedRule() {
+		XWikiNotificationRule rule1 = getDummyNotificationRule();
+		XWikiNotificationRule rule2 = getDummyNotificationRule();
+		assertNull(notificationManager.getNamedRules("testrule"));
+		notificationManager
+				.addNamedRule("testrule", rule1);
+		notificationManager
+				.addNamedRule("testrule", rule2);
+		assertEquals(2, notificationManager.getNamedRules("testrule").size());
+		notificationManager.removeNamedRule("testrule", rule1);
+		assertEquals(1, notificationManager.getNamedRules("testrule").size());
+		notificationManager.removeNamedRule("testrule", rule2);
+		assertNull(notificationManager.getNamedRules("testrule"));
+	}
+
+	public void testRemoveNamedRule() {
+		assertNull(notificationManager.getNamedRules("testrule"));
+		notificationManager
+				.addNamedRule("testrule", getDummyNotificationRule());
+		notificationManager
+				.addNamedRule("testrule", getDummyNotificationRule());
+		assertEquals(2, notificationManager.getNamedRules("testrule").size());
+		notificationManager.removeNamedRule("testrule");
+		assertNull(notificationManager.getNamedRules("testrule"));
+	}
+
+	private XWikiNotificationRule getDummyNotificationRule() {
+		return new XWikiNotificationRule() {
+			public void preverify(XWikiDocument newdoc, XWikiDocument olddoc,
+					XWikiContext context) {
+			}
+
+			public void preverify(XWikiDocument doc, String action,
+					XWikiContext context) {
+			}
+
+			public void verify(XWikiDocument newdoc, XWikiDocument olddoc,
+					XWikiContext context) {
+			}
+
+			public void verify(XWikiDocument doc, String action,
+					XWikiContext context) {
+			}
+		};
+	}
+}
Index: src/main/java/com/xpn/xwiki/notify/XWikiNotificationManager.java
===================================================================
--- src/main/java/com/xpn/xwiki/notify/XWikiNotificationManager.java	(revision 9340)
+++ src/main/java/com/xpn/xwiki/notify/XWikiNotificationManager.java	(working copy)
@@ -28,173 +28,207 @@
 import java.util.Map;
 import java.util.Vector;
 
+/**
+ * Manages general and named notifications rules
+ * 
+ * @version $Id: $
+ */
 public class XWikiNotificationManager {
-    private Vector generalrules = new Vector();
-    private Map namedrules = new HashMap();
+	private Vector generalrules = new Vector();
+	private Map namedrules = new HashMap();
 
-    public XWikiNotificationManager() {
-    }
+	public XWikiNotificationManager() {
+	}
 
-    public void addGeneralRule(XWikiNotificationRule rule) {
-        synchronized (generalrules) {
-            generalrules.add(rule);
-        }
-    }
+	public void addGeneralRule(XWikiNotificationRule rule) {
+		synchronized (generalrules) {
+			generalrules.add(rule);
+		}
+	}
 
-    public void removeGeneralRule(XWikiNotificationRule rule) {
-        synchronized (generalrules) {
-            generalrules.remove(rule);
-        }
-    }
+	public void removeGeneralRule(XWikiNotificationRule rule) {
+		synchronized (generalrules) {
+			generalrules.remove(rule);
+		}
+	}
 
-    public void addNamedRule(String name, XWikiNotificationRule rule) {
-        synchronized (namedrules) {
-            Vector vnamedrules = (Vector) namedrules.get(name);
-            if (vnamedrules==null) {
-                vnamedrules = new Vector();
-                namedrules.put(name, vnamedrules);
-            }
-            vnamedrules.add(rule);
-        }
-    }
+	public void addNamedRule(String name, XWikiNotificationRule rule) {
+		synchronized (namedrules) {
+			Vector vnamedrules = (Vector) namedrules.get(name);
+			if (vnamedrules == null) {
+				vnamedrules = new Vector();
+				namedrules.put(name, vnamedrules);
+			}
+			vnamedrules.add(rule);
+		}
+	}
 
-    public void removeNamedRule(String name) {
-        synchronized (namedrules) {
-            Vector vnamedrules = (Vector) namedrules.get(name);
-            if (vnamedrules!=null) {
-                vnamedrules.remove(name);
-                if (vnamedrules.size()==0)
-                    namedrules.remove(name);
-            }
-        }
-    }
+	/**
+	 * Remove all rules with the given name
+	 */
+	public void removeNamedRule(String name) {
+		synchronized (namedrules) {
+			Vector vnamedrules = (Vector) namedrules.get(name);
+			if (vnamedrules != null) {
+				vnamedrules.removeAllElements();
+			}
+			namedrules.remove(name);
+		}
+	}
 
-    public Vector getNamedRules(String name) {
-        synchronized (namedrules) {
-            return (Vector) namedrules.get(name);
-        }
-    }
+	/**
+	 * Remove the given rule (if it exists) from the rules with the given name
+	 */
+	public void removeNamedRule(String name, XWikiNotificationRule rule) {
+		synchronized (namedrules) {
+			Vector vnamedrules = (Vector) namedrules.get(name);
+			if (vnamedrules != null) {
+				vnamedrules.remove(rule);
+				if (vnamedrules.size() == 0)
+					namedrules.remove(name);
+			}
+		}
+	}
 
-    public void preverify(XWikiDocument newdoc, XWikiDocument olddoc, int event, XWikiContext context) {
-        // Call rules explicitely for any actions of this document
-        Vector vnamedrules;
-        String name = newdoc.getFullName();
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).preverify(newdoc, olddoc, context);
-        }
+	public Vector getNamedRules(String name) {
+		synchronized (namedrules) {
+			return (Vector) namedrules.get(name);
+		}
+	}
 
-        name = context.getDatabase() + ":" + newdoc.getFullName();
+	public void preverify(XWikiDocument newdoc, XWikiDocument olddoc,
+			int event, XWikiContext context) {
+		// Call rules explicitely for any actions of this document
+		Vector vnamedrules;
+		String name = newdoc.getFullName();
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).preverify(newdoc,
+						olddoc, context);
+		}
 
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).preverify(newdoc, olddoc, context);
-        }
+		name = context.getDatabase() + ":" + newdoc.getFullName();
 
-        Vector grules;
-        synchronized (generalrules) {
-            grules = (Vector) generalrules.clone();
-        }
-        for (int i=0;i<grules.size();i++)
-            ((XWikiNotificationRule)grules.get(i)).preverify(newdoc, olddoc, context);
-    }
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).preverify(newdoc,
+						olddoc, context);
+		}
 
-    public void verify(XWikiDocument newdoc, XWikiDocument olddoc, int event, XWikiContext context) {
-        // Call the document notification function itself..
-        newdoc.notify(null, newdoc, olddoc, event, context);
+		Vector grules;
+		synchronized (generalrules) {
+			grules = (Vector) generalrules.clone();
+		}
+		for (int i = 0; i < grules.size(); i++)
+			((XWikiNotificationRule) grules.get(i)).preverify(newdoc, olddoc,
+					context);
+	}
 
-        // Call rules explicitely for any actions of this document
-        Vector vnamedrules;
-        String name = newdoc.getFullName();
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).verify(newdoc, olddoc, context);
-        }
+	public void verify(XWikiDocument newdoc, XWikiDocument olddoc, int event,
+			XWikiContext context) {
+		// Call the document notification function itself..
+		newdoc.notify(null, newdoc, olddoc, event, context);
 
-        name = context.getDatabase() + ":" + newdoc.getFullName();
+		// Call rules explicitely for any actions of this document
+		Vector vnamedrules;
+		String name = newdoc.getFullName();
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).verify(newdoc,
+						olddoc, context);
+		}
 
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).verify(newdoc, olddoc, context);
-        }
+		name = context.getDatabase() + ":" + newdoc.getFullName();
 
-        Vector grules;
-        synchronized (generalrules) {
-            grules = (Vector) generalrules.clone();
-        }
-        for (int i=0;i<grules.size();i++)
-            ((XWikiNotificationRule)grules.get(i)).verify(newdoc, olddoc, context);
-    }
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).verify(newdoc,
+						olddoc, context);
+		}
 
-    public void verify(XWikiDocument doc, String action, XWikiContext context) {
-        // Call rules explicitely for any actions of this document
-        Vector vnamedrules;
-        String name = doc.getFullName();
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).verify(doc, action, context);
-        }
-        name = context.getDatabase() + ":" + doc.getFullName();
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).preverify(doc, action, context);
-        }
-        Vector grules;
-        synchronized (generalrules) {
-            grules = (Vector) generalrules.clone();
-        }
-        for (int i=0;i<grules.size();i++)
-            ((XWikiNotificationRule)grules.get(i)).verify(doc, action, context);
-    }
+		Vector grules;
+		synchronized (generalrules) {
+			grules = (Vector) generalrules.clone();
+		}
+		for (int i = 0; i < grules.size(); i++)
+			((XWikiNotificationRule) grules.get(i)).verify(newdoc, olddoc,
+					context);
+	}
 
-    public void preverify(XWikiDocument doc, String action, XWikiContext context) {
-        // Call rules explicitely for any actions of this document
-        Vector vnamedrules;
-        String name = doc.getFullName();
-        synchronized (namedrules) {
-            vnamedrules = getNamedRules(name);
-            if (vnamedrules!=null)
-             vnamedrules = (Vector) vnamedrules.clone();
-        }
-        if (vnamedrules!=null) {
-            for (int i=0;i<vnamedrules.size();i++)
-               ((XWikiNotificationRule)vnamedrules.get(i)).preverify(doc, action, context);
-        }
-        Vector grules;
-        synchronized (generalrules) {
-            grules = (Vector) generalrules.clone();
-        }
-        for (int i=0;i<grules.size();i++)
-            ((XWikiNotificationRule)grules.get(i)).preverify(doc, action, context);
-    }
+	public void verify(XWikiDocument doc, String action, XWikiContext context) {
+		// Call rules explicitely for any actions of this document
+		Vector vnamedrules;
+		String name = doc.getFullName();
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).verify(doc,
+						action, context);
+		}
+		name = context.getDatabase() + ":" + doc.getFullName();
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).preverify(doc,
+						action, context);
+		}
+		Vector grules;
+		synchronized (generalrules) {
+			grules = (Vector) generalrules.clone();
+		}
+		for (int i = 0; i < grules.size(); i++)
+			((XWikiNotificationRule) grules.get(i))
+					.verify(doc, action, context);
+	}
+
+	public void preverify(XWikiDocument doc, String action, XWikiContext context) {
+		// Call rules explicitely for any actions of this document
+		Vector vnamedrules;
+		String name = doc.getFullName();
+		synchronized (namedrules) {
+			vnamedrules = getNamedRules(name);
+			if (vnamedrules != null)
+				vnamedrules = (Vector) vnamedrules.clone();
+		}
+		if (vnamedrules != null) {
+			for (int i = 0; i < vnamedrules.size(); i++)
+				((XWikiNotificationRule) vnamedrules.get(i)).preverify(doc,
+						action, context);
+		}
+		Vector grules;
+		synchronized (generalrules) {
+			grules = (Vector) generalrules.clone();
+		}
+		for (int i = 0; i < grules.size(); i++)
+			((XWikiNotificationRule) grules.get(i)).preverify(doc, action,
+					context);
+	}
 }
