Giant patch of changes to support OpenFlow 1.3

The following people have contributed to this patch:
- Ali Al-Shabibi <alshabibi.ali@gmail.com>
- Ayaka Koshibe <ayaka@onlab.us>
- Brian O'Connor <bocon@onlab.us>
- Jonathan Hart <jono@onlab.us>
- Matteo Gerola <mgerola@create-net.org>
- Michele Santuari <michele.santuari@create-net.org>
- Pavlin Radoslavov <pavlin@onlab.us>
- Saurav Das <sauravdas@alumni.stanford.edu>
- Toshio Koide <t-koide@onlab.us>
- Yuta HIGUCHI <y-higuchi@onlab.us>

The patch includes the following changes:
- New Floodlight I/O loop / state machine
- New switch/port handling
- New role management (incl. Role.EQUAL)
- Added Floodlight debug framework
- Updates to Controller.java
- Move to Loxigen's OpenflowJ library
- Added OF1.3 support
- Added support for different switches (via DriverManager)
- Updated ONOS modules to use new APIs
- Added and updated unit tests

Change-Id: Ic70a8d50f7136946193d2ba2e4dc0b4bfac5f599
diff --git a/src/main/java/net/floodlightcontroller/debugevent/Event.java b/src/main/java/net/floodlightcontroller/debugevent/Event.java
new file mode 100644
index 0000000..b3e284e
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/Event.java
@@ -0,0 +1,233 @@
+package net.floodlightcontroller.debugevent;
+
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
+import net.onrc.onos.core.packet.IPv4;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.util.HexString;
+
+public class Event {
+    long timestamp;
+    long threadId;
+    String threadName;
+    Object eventData;
+    private Map<String, String> returnMap;
+
+    public Event(long timestamp, long threadId, String threadName, Object eventData) {
+        super();
+        this.timestamp = timestamp;
+        this.threadId = threadId;
+        this.threadName = threadName;
+        this.eventData = eventData;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public long getThreadId() {
+        return threadId;
+    }
+
+    public void setThreadId(long threadId) {
+        this.threadId = threadId;
+    }
+
+    public String getThreadName() {
+        return threadName;
+    }
+
+    public void setThreadName(String threadName) {
+        this.threadName = threadName;
+    }
+
+    public Object geteventData() {
+        return eventData;
+    }
+
+    public void seteventData(Object eventData) {
+        this.eventData = eventData;
+    }
+
+    /**
+     * If an old event (eg. popped from a circular buffer) is being re-used for
+     * storing a new event, it is very important to clear the cached formatted
+     * event, so that the formatting can be redone with the new event data.
+     * Otherwise it will appear as if the circular buffer is not getting updated
+     * at all as old (cached) formatted event is delivered to the user.
+     */
+    public void nullifyCachedFormattedEvent() {
+        this.returnMap = null;
+    }
+
+    @Override
+    public String toString() {
+        return "Event [timestamp=" + timestamp + ", threadId=" + threadId
+               + ", eventData=" + eventData.toString() + "]";
+    }
+
+    public Map<String, String> getFormattedEvent(Class<?> eventClass, String moduleEventName) {
+        if (eventClass == null || !eventClass.equals(eventData.getClass())) {
+            returnMap = new HashMap<String, String>();
+            returnMap.put("Error", "null event data or event-class does not match event-data");
+            return returnMap;
+        }
+        // return cached value if there is one
+        if (returnMap != null)
+            return returnMap;
+
+        returnMap = new HashMap<String, String>();
+        returnMap.put("Timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+                                            .format(timestamp));
+        returnMap.put("Thread Id", String.valueOf(threadId));
+        returnMap.put("Thread Name", String.valueOf(threadName));
+        customFormat(eventClass, eventData, returnMap);
+        return returnMap;
+    }
+
+    private void customFormat(Class<?> clazz, Object eventData,
+                              Map<String, String> retMap) {
+        for (Field f : clazz.getDeclaredFields()) {
+            EventColumn ec = f.getAnnotation(EventColumn.class);
+            if (ec == null) continue;
+            f.setAccessible(true);
+            try {
+                Object obj =  f.get(eventData);
+
+                switch(ec.description()) {
+                    case DPID:
+                        retMap.put(ec.name(), HexString.toHexString((Long) obj));
+                        break;
+                    case MAC:
+                        retMap.put(ec.name(), HexString.toHexString((Long) obj, 6));
+                        break;
+                    case IPv4:
+                        retMap.put(ec.name(), net.onrc.onos.core.packet.IPv4.fromIPv4Address((Integer) obj));
+                        break;
+                    case FLOW_MOD_FLAGS:
+                        int flags = (Integer)obj;
+                        StringBuilder builder = new StringBuilder();
+                        if (flags == 0) {
+                            builder.append("None");
+                        }
+                        else {
+                            if ((flags & OFFlowMod.OFPFF_SEND_FLOW_REM) != 0) {
+                                builder.append("SEND_FLOW_REM ");
+                            }
+                            if ((flags & OFFlowMod.OFPFF_CHECK_OVERLAP) != 0) {
+                                builder.append("CHECK_OVERLAP ");
+                            }
+                            if ((flags & OFFlowMod.OFPFF_EMERG) != 0) {
+                                builder.append("EMERG ");
+                            }
+                        }
+                        retMap.put(ec.name(), builder.toString());
+                        break;
+                    case LIST_IPV4:
+                        @SuppressWarnings("unchecked")
+                        List<Integer> ipv4Addresses = (List<Integer>)obj;
+                        StringBuilder ipv4AddressesStr = new StringBuilder();
+                        if (ipv4Addresses.size() == 0) {
+                            ipv4AddressesStr.append("--");
+                        } else {
+                            for (Integer ipv4Addr : ipv4Addresses) {
+                                ipv4AddressesStr.append(IPv4.fromIPv4Address(ipv4Addr.intValue()));
+                                ipv4AddressesStr.append(" ");
+                            }
+                        }
+                        retMap.put(ec.name(), ipv4AddressesStr.toString());
+                        break;
+                    case LIST_ATTACHMENT_POINT:
+                        @SuppressWarnings("unchecked")
+                        List<SwitchPort> aps = (List<SwitchPort>)obj;
+                        StringBuilder apsStr = new StringBuilder();
+                        if (aps.size() == 0) {
+                            apsStr.append("--");
+                        } else {
+                            for (SwitchPort ap : aps) {
+                                apsStr.append(HexString.toHexString(ap.dpid().value()));
+                                apsStr.append("/");
+                                apsStr.append(ap.port().value());
+                                apsStr.append(" ");
+                            }
+                        }
+                        retMap.put(ec.name(), apsStr.toString());
+                        break;
+                    case LIST_OBJECT:
+                        @SuppressWarnings("unchecked")
+                        List<Object> obl = (List<Object>)obj;
+                        StringBuilder sbldr = new StringBuilder();
+                        if (obl.size() == 0) {
+                            sbldr.append("--");
+                        } else {
+                            for (Object o : obl) {
+                                sbldr.append(o.toString());
+                                sbldr.append(" ");
+                            }
+                        }
+                        retMap.put(ec.name(), sbldr.toString());
+                        break;
+                    case SREF_LIST_OBJECT:
+                        @SuppressWarnings("unchecked")
+                        SoftReference<List<Object>> srefListObj =
+                            (SoftReference<List<Object>>)obj;
+                        List<Object> ol = srefListObj.get();
+                        if (ol != null) {
+                            StringBuilder sb = new StringBuilder();
+                            if (ol.size() == 0) {
+                                sb.append("--");
+                            } else {
+                                for (Object o : ol) {
+                                    sb.append(o.toString());
+                                    sb.append(" ");
+                                }
+                            }
+                            retMap.put(ec.name(), sb.toString());
+                        } else {
+                            retMap.put(ec.name(), "-- reference not available --");
+                        }
+                        break;
+                    case SREF_OBJECT:
+                        @SuppressWarnings("unchecked")
+                        SoftReference<Object> srefObj = (SoftReference<Object>)obj;
+                        if (srefObj == null) {
+                            retMap.put(ec.name(), "--");
+                        } else {
+                            Object o = srefObj.get();
+                            if (o != null) {
+                                retMap.put(ec.name(), o.toString());
+                            } else {
+                                retMap.put(ec.name(),
+                                           "-- reference not available --");
+                            }
+                        }
+                        break;
+                    case STRING:
+                    case OBJECT:
+                    case PRIMITIVE:
+                    default:
+                        retMap.put(ec.name(), obj.toString());
+                }
+            } catch (ClassCastException e) {
+                retMap.put("Error", e.getMessage());
+            } catch (IllegalArgumentException e) {
+                retMap.put("Error", e.getMessage());
+            } catch (IllegalAccessException e) {
+                retMap.put("Error", e.getMessage());
+            }
+        }
+    }
+
+}