diff --git a/build.xml b/build.xml
index 0f95be469b708e6b9763abb7c48783df3a302d98..385c82399e3ab696865d3ce64eafbf642c21ce0c 100644
--- a/build.xml
+++ b/build.xml
@@ -67,10 +67,9 @@
         <include name="jython-2.5.2.jar"/>
         <include name="libthrift-0.7.0.jar"/>
         <include name="guava-13.0.1.jar" />
-	<include name="commons-logging-1.1.1.jar" />
-	<include name="httpclient-4.2.2.jar" />
-	<include name="httpcore-4.2.2.jar" />
-	<include name="json-simple-1.1.1.jar" />
+        <include name="httpclient-4.2.2.jar" />
+        <include name="httpcore-4.2.2.jar" />
+        <include name="json-simple-1.1.1.jar" />
     </patternset>
 
     <path id="classpath">
diff --git a/lib/commons-logging-1.1.1.jar b/lib/commons-logging-1.1.1.jar
deleted file mode 100644
index 1deef144cb17ed2c11c6cdcdcb2d9530fa8d0b47..0000000000000000000000000000000000000000
Binary files a/lib/commons-logging-1.1.1.jar and /dev/null differ
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 5cfe4f090dfabd831df60a5b173aa8bb21513b3e..c4f502236253db5c3463ab6ae66be4f66dd26b9e 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -977,6 +977,7 @@ public class Controller implements IFloodlightProviderService,
                     }
                     else {
                         logError(sw, error);
+
                         // allow registered listeners to receive error messages
                         shouldHandleMessage = true;
                     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index fd6339338ccee39470298b0253de7f4d18bf4311..a3809a1b80e7cfbc6b1e2f86d880ff95e3a37a35 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -50,6 +50,4 @@ public class OFSwitchImpl extends OFSwitchBase {
     public List<Short> getUplinkPorts() {
         return null;
     }
-
-     
 }
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
index d9b26121690df67b26cb3121f5b7bc719cb4c936..f5036f0917f7afec074a97be208b55284edc509f 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
@@ -1,5 +1,6 @@
 package net.floodlightcontroller.firewall;
 
+import org.codehaus.jackson.map.annotate.JsonSerialize;
 import org.openflow.protocol.OFMatch;
 
 import net.floodlightcontroller.packet.Ethernet;
@@ -8,6 +9,7 @@ import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.packet.TCP;
 import net.floodlightcontroller.packet.UDP;
 
+@JsonSerialize(using=FirewallRuleSerializer.class)
 public class FirewallRule implements Comparable<FirewallRule> {
     public int ruleid;
 
@@ -113,7 +115,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
     public boolean isSameAs(FirewallRule r) {
         if (this.action != r.action
                 || this.wildcard_dl_type != r.wildcard_dl_type
-                || (this.wildcard_dl_type == false && this.dl_type == r.dl_type)
+                || (this.wildcard_dl_type == false && this.dl_type != r.dl_type)
                 || this.wildcard_tp_src != r.wildcard_tp_src
                 || (this.wildcard_tp_src == false && this.tp_src != r.tp_src)
                 || this.wildcard_tp_dst != r.wildcard_tp_dst
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9821d97eeaa5d0be4250a8e26f9cc9a2312e436
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
@@ -0,0 +1,56 @@
+package net.floodlightcontroller.firewall;
+
+import java.io.IOException;
+
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.util.MACAddress;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.openflow.util.HexString;
+
+/**
+ * Serialize a FirewallRule object
+ * Implemented to output easily readable MAC, IP addresses
+ * @author Jason Parraga
+ */
+public class FirewallRuleSerializer extends JsonSerializer<FirewallRule> {
+
+    @Override
+    public void serialize(FirewallRule rule, JsonGenerator jGen,
+            SerializerProvider serializer) throws IOException,
+            JsonProcessingException {
+        jGen.writeStartObject();
+        
+        jGen.writeNumberField("ruleid", rule.ruleid);
+        jGen.writeStringField("dpid", HexString.toHexString(rule.dpid));
+        jGen.writeNumberField("in_port", rule.in_port);
+        jGen.writeStringField("dl_src",String.valueOf(MACAddress.valueOf(rule.dl_src)));
+        jGen.writeStringField("dl_dst", String.valueOf(MACAddress.valueOf(rule.dl_dst)));
+        jGen.writeNumberField("dl_type", rule.dl_type);
+        jGen.writeStringField("nw_src_prefix", IPv4.fromIPv4Address(rule.nw_src_prefix));
+        jGen.writeNumberField("nw_src_maskbits", rule.nw_src_maskbits);
+        jGen.writeStringField("nw_dst_prefix", IPv4.fromIPv4Address(rule.nw_dst_prefix));
+        jGen.writeNumberField("nw_dst_maskbits", rule.nw_dst_maskbits);
+        jGen.writeNumberField("nw_proto", rule.nw_proto);
+        jGen.writeNumberField("tp_src", rule.tp_src);
+        jGen.writeNumberField("tp_dst", rule.tp_dst);
+        jGen.writeBooleanField("wildcard_dpid", rule.wildcard_dpid);
+        jGen.writeBooleanField("wildcard_in_port", rule.wildcard_in_port);
+        jGen.writeBooleanField("wildcard_dl_src", rule.wildcard_dl_src);
+        jGen.writeBooleanField("wildcard_dl_dst", rule.wildcard_dl_dst);
+        jGen.writeBooleanField("wildcard_dl_type", rule.wildcard_dl_type);
+        jGen.writeBooleanField("wildcard_nw_src", rule.wildcard_nw_src);
+        jGen.writeBooleanField("wildcard_nw_dst", rule.wildcard_nw_dst);
+        jGen.writeBooleanField("wildcard_nw_proto", rule.wildcard_nw_proto);
+        jGen.writeBooleanField("wildcard_tp_src", rule.wildcard_tp_src);
+        jGen.writeBooleanField("wildcard_tp_dst", rule.wildcard_tp_dst);
+        jGen.writeNumberField("priority", rule.priority);
+        jGen.writeStringField("action", String.valueOf(rule.action));
+        
+        jGen.writeEndObject();
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
index 34d1b4df0cc64523173fbe35ab87be1c40fba91c..d7291a6ca6546a619aaca82c585136f2a4de9f10 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
@@ -23,7 +23,7 @@ public class FirewallRulesResource extends ServerResource {
     protected static Logger log = LoggerFactory.getLogger(FirewallRulesResource.class);
 
     @Get("json")
-    public Object handleRequest() {
+    public List<FirewallRule> retrieve() {
         IFirewallService firewall = 
                 (IFirewallService)getContext().getAttributes().
                 get(IFirewallService.class.getCanonicalName());
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 1d11ac6c3eaba013295154d8bccfb6ef76710799..9ded18add8aa7c949d03c7e0f32d39fa66c942cd 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -558,8 +558,8 @@ public class LinkDiscoveryManager implements IOFMessageListener,
         }
 
         if (isLinkDiscoverySuppressed(sw, port)) {
-            /*
-             * Dont send LLDPs out of this port as suppressLLDPs set
+            /* Dont send LLDPs out of this port as suppressLLDPs set
+             * 
              */
             return;
         }
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
index a9870db97a8502436bceb7ad523312b4bfeff248..2ff0dabfa59c7f6ae7d8e78ffe1c70304e8082c4 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -444,12 +444,12 @@ public class LoadBalancer implements IFloodlightModule,
                             routingEngine.getRoute(srcDap.getSwitchDPID(),
                                                    (short)srcDap.getPort(),
                                                    dstDap.getSwitchDPID(),
-                                                   (short)dstDap.getPort());
+                                                   (short)dstDap.getPort(), 0);
                     Route routeOut = 
                             routingEngine.getRoute(dstDap.getSwitchDPID(),
                                                    (short)dstDap.getPort(),
                                                    srcDap.getSwitchDPID(),
-                                                   (short)srcDap.getPort());
+                                                   (short)srcDap.getPort(), 0);
 
                     // use static flow entry pusher to push flow mod along in and out path
                     // in: match src client (ip, port), rewrite dest from vip ip/port to member ip/port, forward
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
index 93882973ed77caa75586c3f2ae1696fc0a34c816..63b5d1856b00820f5558315d068655b4f3fb459f 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
@@ -24,17 +24,47 @@ import net.floodlightcontroller.routing.Route;
 
 public interface IRoutingService extends IFloodlightService {
 
-    /** Provides a route between src and dst that allows tunnels. */
+    /**
+     * Provides a route between src and dst that allows tunnels. The cookie is provisioned
+     * for callers of getRoute to provide additional information to influence the route
+     * to be returned, if the underlying routing implementation supports choice among
+     * multiple routes.
+     * @param src Source switch DPID.
+     * @param dst Destination switch DPID.
+     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     */
     public Route getRoute(long src, long dst, long cookie);
 
-    /** Provides a route between src and dst, with option to allow or 
-     *  not allow tunnels in the path.*/
+    /** 
+     * Provides a route between src and dst, with option to allow or 
+     *  not allow tunnels in the path.
+     * @param src Source switch DPID.
+     * @param dst Destination switch DPID.
+     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     * @param tunnelEnabled boolean option.
+     */
     public Route getRoute(long src, long dst, long cookie, boolean tunnelEnabled);
 
-
+    /** 
+     * Provides a route between srcPort on src and dstPort on dst.
+     * @param src Source switch DPID.
+     * @param srcPort Source port on source switch.
+     * @param dst Destination switch DPID.
+     * @param dstPort dstPort on Destination switch.
+     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     */
     public Route getRoute(long srcId, short srcPort, 
                              long dstId, short dstPort, long cookie);
 
+    /** 
+     * Provides a route between srcPort on src and dstPort on dst.
+     * @param src Source switch DPID.
+     * @param srcPort Source port on source switch.
+     * @param dst Destination switch DPID.
+     * @param dstPort dstPort on Destination switch.
+     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     * @param tunnelEnabled boolean option.
+     */
     public Route getRoute(long srcId, short srcPort, 
                              long dstId, short dstPort, long cookie,
                              boolean tunnelEnabled);
diff --git a/src/main/java/org/openflow/util/IProducer.java b/src/main/java/org/openflow/util/IProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..789f5a2ba9ebb0a41f3bf3a54ffd3cde08636d56
--- /dev/null
+++ b/src/main/java/org/openflow/util/IProducer.java
@@ -0,0 +1,8 @@
+package org.openflow.util;
+
+public interface IProducer {
+
+	public void registerConsumer   (Class<?> iface, Object anObj);
+	public void deregisterConsumer (Class<?> iface, Object anObj);
+
+}
diff --git a/src/main/java/org/openflow/util/ProducerConsumer.java b/src/main/java/org/openflow/util/ProducerConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..16f71868f07ee94c7feb3def7bf1b3539e7030bb
--- /dev/null
+++ b/src/main/java/org/openflow/util/ProducerConsumer.java
@@ -0,0 +1,217 @@
+package org.openflow.util;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * The following implement a producer/consumer design pattern in which
+ * both producers and consumers explicitly employ a centralized
+ * registration mechanism, and java Interfaces are used as contracts.<br>
+ *
+ */
+public class ProducerConsumer {
+
+	/*
+	 * Class variables
+	 */
+	protected static ProducerConsumer singleton;
+	
+	/*
+	 * Default constructor
+	 */
+	protected ProducerConsumer ()
+	{
+		producerMap = new Hashtable<Class<?>, Set<IProducer>> ();
+	}
+
+	/*
+	 * Instance variables
+	 */
+
+	// Interface/IProducer map
+	protected Map<Class<?>, Set<IProducer>> producerMap;
+	
+
+	/*
+	 * Protected methods
+	 */
+
+	protected void _registerConsumer (Object consumer, Class<?> [] interfaces, Set<Class<?>> iSet, Set<Class<?>> iUniqueSet)
+	{
+		//*...Process all interfaces...*/
+		for (Class<?> iface: interfaces) {
+			
+			//*...Protect against repeated interfaces...*/
+			if (!iUniqueSet.contains (iface)) {
+				iUniqueSet.add (iface);
+
+				Set<IProducer> producers = producerMap.get (iface);
+
+				if (producers != null) {
+					for (IProducer producer: producers)
+						producer.registerConsumer (iface, consumer);
+					iSet.add (iface);
+				}
+
+				//*...Recurse...*/
+				_registerConsumer (consumer, iface.getInterfaces (), iSet, iUniqueSet);
+			}
+		}
+	}
+	
+	protected void _registerConsumer (Object consumer, Class<?> clazz, Set<Class<?>> iSet, Set<Class<?>> iUniqueSet)
+	{
+		if (clazz != null) {
+			//*...Process all interfaces...*/
+			_registerConsumer (consumer, clazz.getInterfaces (), iSet, iUniqueSet);
+			
+			//*...Recurse the class hierarchy...*/
+			_registerConsumer (consumer, clazz.getSuperclass (), iSet, iUniqueSet);
+		}
+	}
+
+	protected int _deregisterConsumer (Object consumer, Class<?> [] interfaces, Set<Class<?>> iUniqueSet)
+	{
+		int count = 0;
+
+		//*...Process all interfaces...*/
+		for (Class<?> iface: interfaces) {
+			
+			//*...Protect against repeated interfaces...*/
+			if (!iUniqueSet.contains (iface)) {
+				iUniqueSet.add (iface);
+
+				Set<IProducer> producers = producerMap.get (iface);
+
+				if (producers != null) {
+					for (IProducer producer: producers)
+						producer.deregisterConsumer (iface, consumer);
+
+					count ++;
+				}
+
+				//*...Recurse...*/
+				count += _deregisterConsumer (consumer, iface.getInterfaces (), iUniqueSet);
+			}
+		}
+		
+		return count;
+	}
+	
+	protected int _deregisterConsumer (Object consumer, Class<?> clazz, Set<Class<?>> iUniqueSet)
+	{
+		int count = 0;
+
+		if (clazz != null) {
+			//*...Process all interfaces...*/
+			count += _deregisterConsumer (consumer, clazz.getInterfaces (), iUniqueSet);
+			
+			//*...Recurse the class hierarchy...*/
+			count += _deregisterConsumer (consumer, clazz.getSuperclass (), iUniqueSet);
+		}
+		
+		return count;
+	}
+
+	/*
+	 * Singleton API
+	 */
+	
+	/**
+	 * @return singleton ProducerConsumer
+	 */
+	public static synchronized ProducerConsumer getSingleton ()
+	{
+		if (singleton == null)
+			singleton = new ProducerConsumer ();
+		
+		return singleton;
+	}
+	
+	/*
+	 * Producer APIs
+	 */
+
+	/**
+	 * Producer registration
+	 * 
+	 * @param producer object that implements IProducer
+	 * @param iface interface supported by the producer
+	 * @return whether there was a previously registered producer,
+	 * 		   or true if one or more the arguments were invalid
+	 */
+	public boolean registerProducer (IProducer producer, Class<?> iface)
+	{
+		if (producer != null && iface != null && iface.isInterface ()) {
+			Set<IProducer> producers = producerMap.get (iface);
+			
+			if (producers == null) {
+				producers = new HashSet<IProducer> ();
+				producerMap.put (iface, producers);
+			}
+
+			return producers.add (producer);
+		}
+		else
+			return true;
+	}
+	
+	/**
+	 * Producer deregistration
+	 * 
+	 * @param producer object that implements IProducer
+	 * @param iface interface supported by the producer
+	 * @return whether the interface/producer pair was removed,
+	 * 		   or false if one or more the arguments were invalid
+	 */
+	public boolean deregisterProducer (IProducer producer, Class<?> iface)
+	{
+		if (producer != null && iface != null && iface.isInterface ()) {
+			Set<IProducer> producers = producerMap.get (iface);
+			
+			if (producers != null)
+				return producers.remove (producer);
+		}
+
+		return false;
+	}
+
+	
+	/*
+	 * Consumer APIs
+	 */
+
+	/**
+	 * Consumer registration
+	 * 
+	 * @param consumer object that implements producer-specific interfaces
+	 * @return set of supported interfaces
+	 */
+	public Set<Class<?>> registerConsumer (Object consumer)
+	{
+		Set<Class<?>> iSet = new HashSet<Class<?>> ();
+		
+		if (consumer != null)
+			_registerConsumer (consumer, consumer.getClass (), iSet, new HashSet<Class<?>> ());
+		
+		return iSet;
+	}
+
+	/**
+	 * Consumer deregistration 
+	 * 
+	 * @param consumer object to deregister
+	 * @return number of unregistered interfaces
+	 */
+	public int deregisterConsumer (Object consumer)
+	{
+		if (consumer != null)
+			return _deregisterConsumer (consumer, consumer.getClass (), new HashSet<Class<?>> ());
+		else
+			return 0;
+	}
+
+}
diff --git a/src/test/java/org/openflow/util/ProducerConsumerTest.java b/src/test/java/org/openflow/util/ProducerConsumerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec8ab27e17742a6235d74a00f3a3d7bf1f6c88cb
--- /dev/null
+++ b/src/test/java/org/openflow/util/ProducerConsumerTest.java
@@ -0,0 +1,405 @@
+package org.openflow.util;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ProducerConsumerTest {
+
+	protected static interface _IConsumer {}
+	
+	protected static interface _IFace1 {
+		void method1 (Object anArg);
+	}
+
+	protected static interface _IFace2 {
+		void method2 (Object anArg);
+	}
+
+	protected static interface _IFace3 {}
+	
+	protected static Class<?> [] _iface1List  = {_IFace1.class};
+	protected static Class<?> [] _iface12List = {_IFace1.class, _IFace2.class};
+	protected static Class<?> [] _iface23List = {_IFace2.class, _IFace3.class};
+	
+	protected abstract static class _BaseConsumer implements _IConsumer
+	{
+		Class<?> [] ifaceList;
+		
+		_BaseConsumer (Class<?> [] ifaceList)
+		{
+			this.ifaceList = ifaceList;
+		}
+
+		int registeredCount ()
+		{
+			Set<Class<?>> supportedIfaces = ProducerConsumer.getSingleton ().registerConsumer (this);
+			int			  count			  = 0;
+			
+			for (Class<?> iface: ifaceList)
+				if (supportedIfaces.contains (iface))
+					count++;
+			
+			return count;				
+		}
+
+		boolean registerConsumer ()
+		{
+			return registeredCount () == ifaceList.length;
+		}
+
+	}
+
+	protected abstract static class _BaseProducer implements IProducer
+	{
+		Class<?> []				   ifaceList;
+		Map<Class<?>, Set<Object>> ifaceMap = new Hashtable<Class<?>, Set<Object>> ();
+
+		protected _BaseProducer (Class<?> [] ifaceList)
+		{
+			this.ifaceList = ifaceList;
+		}
+
+		protected int registerProducer ()
+		{
+			int count = 0;
+
+			for (Class<?> iface: ifaceList) {
+				if (iface.isInterface ()) {
+					if (ProducerConsumer.getSingleton ().registerProducer (this, iface))
+						count++;
+				}
+			}
+			
+			return count;
+		}
+
+		protected int deregisterProducer ()
+		{
+			int count = 0;
+
+			for (Class<?> iface: ifaceList) {
+				if (iface.isInterface ()) {
+					if (ProducerConsumer.getSingleton ().deregisterProducer (this, iface))
+						count ++;
+				}
+			}
+			
+			return count;
+		}
+		
+		protected int consumerCount ()
+		{
+			int count = 0;
+		
+			for (Class<?> iface: ifaceList) {
+				Set<Object> aSet = ifaceMap.get (iface);
+				
+				if (aSet != null)
+					count += aSet.size ();
+			}
+
+			return count;
+		}
+		
+		protected abstract int runCount ();
+
+		@Override
+		public void registerConsumer (Class<?> iface, Object anObj)
+		{
+			Set<Object> consumers = ifaceMap.get (iface);
+			
+			if (consumers == null) {
+				consumers = new HashSet<Object> ();
+				ifaceMap.put (iface, consumers);
+			}
+
+			consumers.add (anObj);
+		}
+
+		@Override
+		public void deregisterConsumer (Class<?> iface, Object anObj)
+		{
+			Set<Object> consumers = ifaceMap.get (iface);
+			
+			if (consumers != null)
+				consumers.remove (anObj);
+		}
+		
+	}
+	
+	protected static class _Consumer1 extends _BaseConsumer implements _IFace1 {
+
+		protected _Consumer1 ()
+		{
+			this (_iface1List);
+		}
+
+		protected _Consumer1 (Class<?>[] ifaceList)
+		{
+			super (ifaceList);
+		}
+
+		@Override
+		public void method1 (Object anArg) {}
+		
+	}
+
+	protected static class _Consumer12 extends _Consumer1 implements _IFace1, _IFace2 {
+
+		protected _Consumer12 ()
+		{
+			super (_iface12List);
+		}
+
+		@Override
+		public void method2 (Object anArg) {}
+
+	}
+
+	protected static class _Producer1 extends _BaseProducer {
+
+		protected _Producer1 ()
+		{
+			super (_iface1List);
+		}
+
+		@Override
+		protected int runCount ()
+		{
+			int count = 0;
+
+			for (Class<?> iface: ifaceList) {
+				Set<Object> aSet = ifaceMap.get (iface);
+				
+				if (aSet != null) {
+					if (iface == _IFace1.class) {
+						for (Object anObj: aSet) {
+							((_IFace1) anObj).method1 (anObj);
+							count++;
+						}
+					}
+				}
+			}
+
+			return count;
+		}
+		
+	}
+	
+	protected static class _Producer12 extends _BaseProducer {
+
+		protected _Producer12 ()
+		{
+			super (_iface12List);
+		}
+
+		@Override
+		protected int runCount ()
+		{
+			int count = 0;
+
+			for (Class<?> iface: ifaceList) {
+				Set<Object> aSet = ifaceMap.get (iface);
+				
+				if (aSet != null) {
+					if		(iface == _IFace1.class) {
+						for (Object anObj: aSet) {
+							((_IFace1) anObj).method1 (anObj);
+							count++;
+						}
+					}
+					else if (iface == _IFace2.class) {
+						for (Object anObj: aSet) {
+							((_IFace2) anObj).method2 (anObj);
+							count++;
+						}
+					}
+				}
+			}
+
+			return count;
+		}
+		
+	}
+	
+	protected static class _Producer23 extends _BaseProducer {
+
+		protected _Producer23 ()
+		{
+			super (_iface23List);
+		}
+
+		@Override
+		protected int runCount ()
+		{
+			int count = 0;
+
+			for (Class<?> iface: ifaceList) {
+				Set<Object> aSet = ifaceMap.get (iface);
+				
+				if (aSet != null) {
+					if		(iface == _IFace2.class) {
+						for (Object anObj: aSet) {
+							((_IFace2) anObj).method2 (anObj);
+							count++;
+						}
+					}
+					else if (iface == _IFace3.class) {
+						for (Object anObj: aSet) {
+							_IFace3 iface3 = (_IFace3) anObj;
+							
+							if (iface3 != null)
+								count++;
+						}
+					}
+				}
+			}
+
+			return count;
+		}
+		
+	}
+	
+	protected List<_BaseProducer> producers = new ArrayList<_BaseProducer> ();
+	protected List<_BaseConsumer> consumers = new ArrayList<_BaseConsumer> ();
+
+	protected static final String _REG_P_STR_   = "Registering producers";
+	protected static final String _REG_C_STR_   = "Registering consumers";
+	protected static final String _C_CNT_STR_   = "Consumer count";
+	protected static final String _P_CNT_STR_   = "Producer run count";
+	protected static final String _DREG_C_STR_  = "Deregistering consumers";
+	protected static final String _P_C_CNT_STR_ = "Producer client count";
+	protected static final String _DREG_P_STR_  = "Deregistering producers";
+	protected static final String _DREG_P2_STR_ = "Deregistering producers (again)";
+
+	protected static int _MSG_FILL_LENGTH_;
+	
+	static {
+		String [] msgList = {_REG_P_STR_, _REG_C_STR_, _C_CNT_STR_, _P_CNT_STR_, _DREG_C_STR_,
+							 _P_C_CNT_STR_, _DREG_P_STR_, _DREG_P2_STR_};
+		int		  maxLen  = 0;
+		
+		for (String str: msgList)
+			if (str.length () > maxLen)
+				maxLen = str.length ();
+		
+		_MSG_FILL_LENGTH_ = maxLen + 3;
+	}
+	
+	protected static void evalTest (String msg, Object expected, Object have)
+	{
+		boolean	     success = (expected.equals (have));
+		@SuppressWarnings("resource")
+		PrintStream  pStream = success ? System.out : System.err;
+		@SuppressWarnings("resource")
+		PrintStream  oStream = success ? System.err : System.out;
+		StringBuffer strBuff = new StringBuffer (msg);
+		
+		oStream.flush ();
+		
+		for (int i = 0; i < _MSG_FILL_LENGTH_ - msg.length (); i++)
+			strBuff.append (".");
+		
+		strBuff.append (success ? "PASSED" : "FAILED");
+
+		if (!success)
+			strBuff.append ("; expected " + expected + ", have " + have);
+
+		pStream.println (strBuff.toString ());
+		pStream.flush ();		
+	}
+
+	protected int registerProducers ()
+	{
+		_BaseProducer [] producerList = {new _Producer1 (), new _Producer12 (), new _Producer23 ()};
+		int				 count		  = 0;
+		
+		for (_BaseProducer producer: producerList) {
+			count += producer.registerProducer ();
+			producers.add (producer);
+		}
+
+		return count;
+	}
+
+	protected int deregisterProducers ()
+	{
+		int count = 0;
+
+		for (_BaseProducer producer: producers)
+			count += producer.deregisterProducer ();
+
+		return count;
+	}
+	
+	protected int consumerCount ()
+	{
+		int count = 0;
+		
+		for (_BaseProducer producer: producers)
+			count += producer.consumerCount ();
+		
+		return count;	
+	}
+
+	protected boolean registerConsumers ()
+	{
+		_BaseConsumer [] consumerList = {new _Consumer1 (), new _Consumer12 ()};
+		boolean			 cRegistered  = true;
+		
+		for (_BaseConsumer consumer: consumerList) {
+			consumers.add (consumer);
+			cRegistered &= consumer.registerConsumer ();
+		}
+		
+		return cRegistered;		
+	}
+
+	protected int deregisterConsumers ()
+	{
+		int count = 0;
+
+		for (_BaseConsumer consumer: consumers)
+			count += ProducerConsumer.getSingleton ().deregisterConsumer (consumer);
+		
+		return count;
+	}
+
+	protected int runCount ()
+	{
+		int count = 0;
+		
+		for (_BaseProducer producer: producers)
+			count += producer.runCount ();
+		
+		return count;	
+	}
+
+	protected void run ()
+	{
+		evalTest (_REG_P_STR_,   5,	   registerProducers ());
+		evalTest (_REG_C_STR_,   true, registerConsumers ());
+		evalTest (_C_CNT_STR_,   6,    consumerCount ());
+		evalTest (_P_CNT_STR_,	 6,	   runCount ());
+		evalTest (_DREG_C_STR_,  3,	   deregisterConsumers ());
+		evalTest (_P_C_CNT_STR_, 0,	   consumerCount ());
+		evalTest (_DREG_P_STR_,	 5,	   deregisterProducers ());
+		evalTest (_DREG_P2_STR_, 0,	   deregisterProducers ());
+	}
+
+	/**
+	 * @param args
+	 */
+	public static void main (String[] args)
+	{
+		ProducerConsumerTest test = new ProducerConsumerTest ();
+		
+		test.run ();
+	}
+
+}