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 (); + } + +}