Added cubby-holes for new projects.
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/Dpid.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/Dpid.java
new file mode 100644
index 0000000..5544354
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/Dpid.java
@@ -0,0 +1,74 @@
+package net.onrc.onos.of.ctl.util;
+
+import org.projectfloodlight.openflow.util.HexString;
+
+/**
+ * The class representing a network switch DPID.
+ * This class is immutable.
+ */
+public final class Dpid {
+ private static final long UNKNOWN = 0;
+ private final long value;
+
+ /**
+ * Default constructor.
+ */
+ public Dpid() {
+ this.value = Dpid.UNKNOWN;
+ }
+
+ /**
+ * Constructor from a long value.
+ *
+ * @param value the value to use.
+ */
+ public Dpid(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Constructor from a string.
+ *
+ * @param value the value to use.
+ */
+ public Dpid(String value) {
+ this.value = HexString.toLong(value);
+ }
+
+ /**
+ * Get the value of the DPID.
+ *
+ * @return the value of the DPID.
+ */
+ public long value() {
+ return value;
+ }
+
+ /**
+ * Convert the DPID value to a ':' separated hexadecimal string.
+ *
+ * @return the DPID value as a ':' separated hexadecimal string.
+ */
+ @Override
+ public String toString() {
+ return HexString.toHexString(this.value);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Dpid)) {
+ return false;
+ }
+
+ Dpid otherDpid = (Dpid) other;
+
+ return value == otherDpid.value;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash += 31 * hash + (int) (value ^ value >>> 32);
+ return hash;
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/DummySwitchForTesting.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/DummySwitchForTesting.java
new file mode 100644
index 0000000..a8eabce
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/DummySwitchForTesting.java
@@ -0,0 +1,360 @@
+package net.onrc.onos.of.ctl.util;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.jboss.netty.channel.Channel;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.onrc.onos.of.ctl.IOFSwitch;
+import net.onrc.onos.of.ctl.Role;
+import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService;
+import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
+
+public class DummySwitchForTesting implements IOFSwitch {
+
+ protected static final Logger log = LoggerFactory.getLogger(DummySwitchForTesting.class);
+
+ private Channel channel;
+ private boolean connected = false;
+ private OFVersion ofv = OFVersion.OF_10;
+
+ private Collection<OFPortDesc> ports;
+
+ private DatapathId datapathId;
+
+ private Set<OFCapabilities> capabilities;
+
+ private int buffers;
+
+ private byte tables;
+
+ private String stringId;
+
+ private Role role;
+
+ @Override
+ public void disconnectSwitch() {
+ this.channel.close();
+ }
+
+ @Override
+ public void write(OFMessage m) throws IOException {
+ this.channel.write(m);
+
+ }
+
+ @Override
+ public void write(List<OFMessage> msglist) throws IOException {
+ for (OFMessage m : msglist) {
+ this.channel.write(m);
+ }
+
+ }
+
+ @Override
+ public Date getConnectedSince() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getNextTransactionId() {
+ return 0;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return this.connected;
+ }
+
+ @Override
+ public void setConnected(boolean connected) {
+ this.connected = connected;
+
+ }
+
+ @Override
+ public void flush() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setChannel(Channel channel) {
+ this.channel = channel;
+
+ }
+
+ @Override
+ public long getId() {
+ if (this.stringId == null) {
+ throw new RuntimeException("Features reply has not yet been set");
+ }
+ return this.datapathId.getLong();
+ }
+
+ @Override
+ public String getStringId() {
+ // TODO Auto-generated method stub
+ return "DummySwitch";
+ }
+
+ @Override
+ public int getNumBuffers() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Set<OFCapabilities> getCapabilities() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public byte getNumTables() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public OFDescStatsReply getSwitchDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void cancelFeaturesReply(int transactionId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Set<OFActionType> getActions() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setOFVersion(OFVersion version) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public OFVersion getOFVersion() {
+ return this.ofv;
+ }
+
+ @Override
+ public Collection<OFPortDesc> getEnabledPorts() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Collection<Integer> getEnabledPortNumbers() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public OFPortDesc getPort(int portNumber) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public OFPortDesc getPort(String portName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public OrderedCollection<PortChangeEvent> processOFPortStatus(
+ OFPortStatus ps) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Collection<OFPortDesc> getPorts() {
+ return ports;
+ }
+
+ @Override
+ public boolean portEnabled(int portName) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public OrderedCollection<PortChangeEvent> setPorts(
+ Collection<OFPortDesc> p) {
+ this.ports = p;
+ return null;
+ }
+
+ @Override
+ public Map<Object, Object> getAttributes() {
+ return null;
+ }
+
+ @Override
+ public boolean hasAttribute(String name) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return Boolean.FALSE;
+ }
+
+ @Override
+ public void setAttribute(String name, Object value) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Object removeAttribute(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void deliverStatisticsReply(OFMessage reply) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void cancelStatisticsReply(int transactionId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void cancelAllStatisticsReplies() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
+ throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void clearAllFlowMods() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Role getRole() {
+ return this.role;
+ }
+
+ @Override
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ @Override
+ public U64 getNextGenerationId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setDebugCounterService(IDebugCounterService debugCounter)
+ throws CounterException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void startDriverHandshake() throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isDriverHandshakeComplete() {
+ return true;
+ }
+
+ @Override
+ public void processDriverHandshakeMessage(OFMessage m) {
+
+ }
+
+ @Override
+ public void setTableFull(boolean isFull) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFeaturesReply(OFFeaturesReply featuresReply) {
+ if (featuresReply == null) {
+ log.error("Error setting featuresReply for switch: {}", getStringId());
+ return;
+ }
+ this.datapathId = featuresReply.getDatapathId();
+ this.capabilities = featuresReply.getCapabilities();
+ this.buffers = (int) featuresReply.getNBuffers();
+ this.tables = (byte) featuresReply.getNTables();
+ this.stringId = this.datapathId.toString();
+
+ }
+
+ @Override
+ public void setPortDescReply(OFPortDescStatsReply portDescReply) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void handleMessage(OFMessage m) {
+ log.info("Got packet {} but I am dumb so I don't know what to do.", m);
+ }
+
+ @Override
+ public boolean portEnabled(String portName) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public OrderedCollection<PortChangeEvent> comparePorts(
+ Collection<OFPortDesc> p) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/EnumBitmaps.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/EnumBitmaps.java
new file mode 100644
index 0000000..fe6ccc0
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/EnumBitmaps.java
@@ -0,0 +1,149 @@
+package net.onrc.onos.of.ctl.util;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * A utility class to convert between integer based bitmaps for (OpenFlow)
+ * flags and Enum and EnumSet based representations.
+ *
+ * The enum used to represent individual flags needs to implement the
+ * BitmapableEnum interface.
+ *
+ * Example:
+ * {@code
+ * int bitmap = 0x11; // OFPPC_PORT_DOWN | OFPPC_NO_STP
+ * EnumSet<OFPortConfig> s = toEnumSet(OFPortConfig.class, bitmap);
+ * // s will contain OFPPC_PORT_DOWN and OFPPC_NO_STP
+ * }
+ *
+ * {@code
+ * EnumSet<OFPortConfig> s = EnumSet.of(OFPPC_NO_STP, OFPPC_PORT_DOWN);
+ * int bitmap = toBitmap(s); // returns 0x11
+ * }
+ *
+ */
+public final class EnumBitmaps {
+
+
+ private EnumBitmaps() { }
+
+ /**
+ * Enums used to represent individual flags needs to implement this
+ * interface.
+ */
+ public interface BitmapableEnum {
+ /** Return the value in the bitmap that the enum constant represents.
+ * The returned value must have only a single bit set. E.g.,1 << 3
+ */
+ int getValue();
+ }
+
+
+ /**
+ * Convert an integer bitmap to an EnumSet.
+ *
+ * See class description for example
+ * @param type The Enum class to use. Must implement BitmapableEnum
+ * @param bitmap The integer bitmap
+ * @return A newly allocated EnumSet representing the bits set in the
+ * bitmap
+ * @throws NullPointerException if type is null
+ * @throws IllegalArgumentException if any enum constant from type has
+ * more than one bit set.
+ * @throws IllegalArgumentException if the bitmap has any bits set not
+ * represented by an enum constant.
+ */
+ public static <E extends Enum<E> & BitmapableEnum>
+ EnumSet<E> toEnumSet(Class<E> type, int bitmap) {
+ if (type == null) {
+ throw new NullPointerException("Given enum type must not be null");
+ }
+ EnumSet<E> s = EnumSet.noneOf(type);
+ // allSetBitmap will eventually have all valid bits for the given
+ // type set.
+ int allSetBitmap = 0;
+ for (E element: type.getEnumConstants()) {
+ if (Integer.bitCount(element.getValue()) != 1) {
+ String msg = String.format("The %s (%x) constant of the " +
+ "enum %s is supposed to represent a bitmap entry but " +
+ "has more than one bit set.",
+ element.toString(), element.getValue(), type.getName());
+ throw new IllegalArgumentException(msg);
+ }
+ allSetBitmap |= element.getValue();
+ if ((bitmap & element.getValue()) != 0) {
+ s.add(element);
+ }
+ }
+ if (((~allSetBitmap) & bitmap) != 0) {
+ // check if only valid flags are set in the given bitmap
+ String msg = String.format("The bitmap %x for enum %s has " +
+ "bits set that are presented by any enum constant",
+ bitmap, type.getName());
+ throw new IllegalArgumentException(msg);
+ }
+ return s;
+ }
+
+ /**
+ * Return the bitmap mask with all possible bits set. E.g., If a bitmap
+ * has the individual flags 0x1, 0x2, and 0x8 (note the missing 0x4) then
+ * the mask will be 0xb (1011 binary)
+ *
+ * @param type The Enum class to use. Must implement BitmapableEnum
+ * @throws NullPointerException if type is null
+ * @throws IllegalArgumentException if any enum constant from type has
+ * more than one bit set
+ * @return an integer with all possible bits for the given bitmap enum
+ * type set.
+ */
+ public static <E extends Enum<E> & BitmapableEnum>
+ int getMask(Class<E> type) {
+ if (type == null) {
+ throw new NullPointerException("Given enum type must not be null");
+ }
+ // allSetBitmap will eventually have all valid bits for the given
+ // type set.
+ int allSetBitmap = 0;
+ for (E element: type.getEnumConstants()) {
+ if (Integer.bitCount(element.getValue()) != 1) {
+ String msg = String.format("The %s (%x) constant of the " +
+ "enum %s is supposed to represent a bitmap entry but " +
+ "has more than one bit set.",
+ element.toString(), element.getValue(), type.getName());
+ throw new IllegalArgumentException(msg);
+ }
+ allSetBitmap |= element.getValue();
+ }
+ return allSetBitmap;
+ }
+
+ /**
+ * Convert the given EnumSet to the integer bitmap representation.
+ * @param set The EnumSet to convert. The enum must implement
+ * BitmapableEnum
+ * @return the integer bitmap
+ * @throws IllegalArgumentException if an enum constant from the set (!) has
+ * more than one bit set
+ * @throws NullPointerException if the set is null
+ */
+ public static <E extends Enum<E> & BitmapableEnum>
+ int toBitmap(Set<E> set) {
+ if (set == null) {
+ throw new NullPointerException("Given set must not be null");
+ }
+ int bitmap = 0;
+ for (E element: set) {
+ if (Integer.bitCount(element.getValue()) != 1) {
+ String msg = String.format("The %s (%x) constant in the set " +
+ "is supposed to represent a bitmap entry but " +
+ "has more than one bit set.",
+ element.toString(), element.getValue());
+ throw new IllegalArgumentException(msg);
+ }
+ bitmap |= element.getValue();
+ }
+ return bitmap;
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/FilterIterator.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/FilterIterator.java
new file mode 100644
index 0000000..fdde82c
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/FilterIterator.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2012, Big Switch Networks, Inc.
+ * Originally created by David Erickson, Stanford University
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ **/
+
+package net.onrc.onos.of.ctl.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator that will filter values from an iterator and return only
+ * those values that match the predicate.
+ */
+public abstract class FilterIterator<T> implements Iterator<T> {
+ protected Iterator<T> subIterator;
+ protected T next;
+
+ /**
+ * Construct a filter iterator from the given sub iterator.
+ *
+ * @param subIterator the sub iterator over which we'll filter
+ */
+ public FilterIterator(Iterator<T> subIterator) {
+ super();
+ this.subIterator = subIterator;
+ }
+
+ /**
+ * Check whether the given value should be returned by the
+ * filter.
+ *
+ * @param value the value to check
+ * @return true if the value should be included
+ */
+ protected abstract boolean matches(T value);
+
+ // ***********
+ // Iterator<T>
+ // ***********
+
+ @Override
+ public boolean hasNext() {
+ if (next != null) {
+ return true;
+ }
+
+ while (subIterator.hasNext()) {
+ next = subIterator.next();
+ if (matches(next)) {
+ return true;
+ }
+ }
+ next = null;
+ return false;
+ }
+
+ @Override
+ public T next() {
+ if (hasNext()) {
+ T cur = next;
+ next = null;
+ return cur;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/InstanceId.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/InstanceId.java
new file mode 100644
index 0000000..861dec6
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/InstanceId.java
@@ -0,0 +1,47 @@
+package net.onrc.onos.of.ctl.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * The class representing an ONOS Instance ID.
+ *
+ * This class is immutable.
+ */
+public final class InstanceId {
+ private final String id;
+
+ /**
+ * Constructor from a string value.
+ *
+ * @param id the value to use.
+ */
+ public InstanceId(String id) {
+ this.id = checkNotNull(id);
+ checkArgument(!id.isEmpty(), "Empty ONOS Instance ID");
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof InstanceId)) {
+ return false;
+ }
+
+ InstanceId that = (InstanceId) obj;
+ return this.id.equals(that.id);
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/IterableIterator.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/IterableIterator.java
new file mode 100644
index 0000000..79f3c9d
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/IterableIterator.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2012 Big Switch Networks, Inc.
+ * Originally created by David Erickson, Stanford University
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ **/
+
+package net.onrc.onos.of.ctl.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Iterator over all values in an iterator of iterators.
+ *
+ * @param <T> the type of elements returned by this iterator
+ */
+public class IterableIterator<T> implements Iterator<T> {
+ Iterator<? extends Iterable<T>> subIterator;
+ Iterator<T> current = null;
+
+ public IterableIterator(Iterator<? extends Iterable<T>> subIterator) {
+ super();
+ this.subIterator = subIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (current == null) {
+ if (subIterator.hasNext()) {
+ current = subIterator.next().iterator();
+ } else {
+ return false;
+ }
+ }
+ while (!current.hasNext() && subIterator.hasNext()) {
+ current = subIterator.next().iterator();
+ }
+
+ return current.hasNext();
+ }
+
+ @Override
+ public T next() {
+ if (hasNext()) {
+ return current.next();
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ if (hasNext()) {
+ current.remove();
+ }
+ throw new NoSuchElementException();
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LRUHashMap.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LRUHashMap.java
new file mode 100644
index 0000000..17f9354
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LRUHashMap.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2011, Big Switch Networks, Inc.
+ * Originally created by David Erickson, Stanford University
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ **/
+
+package net.onrc.onos.of.ctl.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LRUHashMap<K, V> extends LinkedHashMap<K, V> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final int capacity;
+
+ public LRUHashMap(int capacity) {
+ super(capacity + 1, 0.75f, true);
+ this.capacity = capacity;
+ }
+
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > capacity;
+ }
+
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LinkedHashSetWrapper.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LinkedHashSetWrapper.java
new file mode 100644
index 0000000..629e536
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/LinkedHashSetWrapper.java
@@ -0,0 +1,32 @@
+package net.onrc.onos.of.ctl.util;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+import com.google.common.collect.ForwardingCollection;
+
+/**
+ * A simple wrapper / forwarder that forwards all calls to a LinkedHashSet.
+ * This wrappers sole reason for existence is to implement the
+ * OrderedCollection marker interface.
+ *
+ */
+public class LinkedHashSetWrapper<E>
+ extends ForwardingCollection<E> implements OrderedCollection<E> {
+ private final Collection<E> delegate;
+
+ public LinkedHashSetWrapper() {
+ super();
+ this.delegate = new LinkedHashSet<E>();
+ }
+
+ public LinkedHashSetWrapper(Collection<? extends E> c) {
+ super();
+ this.delegate = new LinkedHashSet<E>(c);
+ }
+
+ @Override
+ protected Collection<E> delegate() {
+ return this.delegate;
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/MultiIterator.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/MultiIterator.java
new file mode 100644
index 0000000..693a8bf
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/MultiIterator.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2012 Big Switch Networks, Inc.
+ * Originally created by David Erickson, Stanford University
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ **/
+
+package net.onrc.onos.of.ctl.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Iterator over all values in an iterator of iterators.
+ *
+ * @param <T> the type of elements returned by this iterator
+ */
+public class MultiIterator<T> implements Iterator<T> {
+ Iterator<Iterator<T>> subIterator;
+ Iterator<T> current = null;
+
+ public MultiIterator(Iterator<Iterator<T>> subIterator) {
+ super();
+ this.subIterator = subIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (current == null) {
+ if (subIterator.hasNext()) {
+ current = subIterator.next();
+ } else {
+ return false;
+ }
+ }
+ while (!current.hasNext() && subIterator.hasNext()) {
+ current = subIterator.next();
+ }
+
+ return current.hasNext();
+ }
+
+ @Override
+ public T next() {
+ if (hasNext()) {
+ return current.next();
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ if (hasNext()) {
+ current.remove();
+ }
+ throw new NoSuchElementException();
+ }
+}
diff --git a/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/OrderedCollection.java b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/OrderedCollection.java
new file mode 100644
index 0000000..f032212
--- /dev/null
+++ b/of-save/ctl/src/main/java/net/onrc/onos/of/ctl/util/OrderedCollection.java
@@ -0,0 +1,14 @@
+package net.onrc.onos.of.ctl.util;
+
+import java.util.Collection;
+
+/**
+ * A marker interface indicating that this Collection defines a particular
+ * iteration order. The details about the iteration order are specified by
+ * the concrete implementation.
+ *
+ * @param <E>
+ */
+public interface OrderedCollection<E> extends Collection<E> {
+
+}