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