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/CircularBuffer.java b/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java
new file mode 100644
index 0000000..f1a6db3
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java
@@ -0,0 +1,95 @@
+package net.floodlightcontroller.debugevent;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingDeque;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CircularBuffer<T> implements Iterable<T>{
+    protected static Logger log = LoggerFactory.getLogger(CircularBuffer.class);
+    private final LinkedBlockingDeque<T> buffer;
+
+    public CircularBuffer(int capacity) {
+        this.buffer = new LinkedBlockingDeque<T>(capacity);
+    }
+
+    /**
+     * Adding an element to the circular buffer implies adding the element to
+     * the tail of the deque. In doing so, if the capacity of the buffer has
+     * been exhausted, then the deque's head should be removed to preserve the
+     * circular nature of the buffer. A LinkedBlockingDeque is used because of its
+     * concurrent nature and the fact that adding to tail and removing from head are
+     * both O(1) operations. The removed head is returned to the caller for reuse.
+     *
+     * @param e    the element to be added
+     * @return     removed element (for reuse) or null
+     */
+    public T add(T e) {
+        T oldE = null;
+        while (!buffer.offerLast(e)) {
+            oldE = buffer.poll();
+        }
+        return oldE;
+    }
+
+    /**
+     * The basic idea here is that an ArrayList has been passed in, which may or may not
+     * have a size bigger that the actual number of elements that are meant to
+     * be flushed to the Circular Buffer. Thus the 'uptoIndex' parameter specifies
+     * the number of elements that need to be flushed starting from index 0.
+     * Note that after flushing, the circular buffer may return a memory unit (of type T)
+     * for reuse in the list, if the circular buffer popped off memory to preserve
+     * its circular nature. Or it may just return null if nothing was popped off.
+     * Either way, the list that is returned by this method, is of the SAME SIZE
+     * as the list passed in, as ArrayLists can hold null elements. The only difference
+     * is that the list returned will have elements that reference old popped-off memory
+     * from the circular-buffer or null.
+     *
+     * @param elist         the ArrayList to flush into the circular buffer.
+     * @param uptoIndex     flush starting from index 0 upto but not including
+     *                      index 'uptoIndex'.
+     * @return              the 'elist' passed in with members now pointing to
+     *                      to null or old-memory for reuse. The returned list
+     *                      if of the same size as 'elist'.
+     */
+    public ArrayList<T> addAll(ArrayList<T> elist, int uptoIndex) {
+        if (uptoIndex > elist.size()) {
+            log.error("uptoIndex is greater than elist size .. aborting addAll");
+            return elist;
+        }
+        for (int index=0; index < uptoIndex; index++) {
+            T e = elist.get(index);
+            if (e != null) {
+                elist.set(index, add(e));
+            }
+        }
+        return elist;
+    }
+
+    /**
+     * Returns an iterator over the elements in the circular buffer in proper sequence.
+     * The elements will be returned in order from most-recent to oldest.
+     * The returned Iterator is a "weakly consistent" iterator that will never
+     * throw ConcurrentModificationException, and guarantees to traverse elements
+     * as they existed upon construction of the iterator, and may (but is not
+     * guaranteed to) reflect any modifications subsequent to construction.
+     */
+    @Override
+    public Iterator<T> iterator() {
+        return buffer.descendingIterator();
+    }
+
+    public int size() {
+        return buffer.size();
+    }
+
+    /**
+     *  Atomically removes all elements in the circular buffer
+     */
+    public void clear() {
+        buffer.clear();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
new file mode 100644
index 0000000..e167b26
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
@@ -0,0 +1,506 @@
+package net.floodlightcontroller.debugevent;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugevent.web.DebugEventRoutable;
+import net.floodlightcontroller.restserver.IRestApiService;
+
+import com.google.common.collect.Sets;
+/**
+ * This class implements a central store for all events used for debugging the
+ * system. The basic idea is that given the functionality provided by this class,
+ * it should be unnecessary to resort to scraping through system DEBUG/TRACE logs
+ * to understand behavior in a running system.
+ *
+ * @author saurav
+ */
+public class DebugEvent implements IFloodlightModule, IDebugEventService {
+    protected static Logger log = LoggerFactory.getLogger(DebugEvent.class);
+
+    /**
+     *  Every registered event type gets an event id, the value for which is obtained
+     *  while holding the lock.
+     */
+    protected int eventIdCounter = 0;
+    protected Object eventIdLock = new Object();
+
+    private static final int PCT_LOCAL_CAP = 10; // % of global capacity
+    private static final int MIN_LOCAL_CAPACITY = 10; //elements
+
+    /**
+     * Event Information
+     */
+    public class EventInfo {
+        int eventId;
+        boolean enabled;
+        int bufferCapacity;
+        EventType etype;
+        String eventDesc;
+        String eventName;
+        String moduleName;
+        String moduleEventName;
+        Class<?> eventClass;
+        String[] metaData;
+
+        public EventInfo(int eventId, boolean enabled, int bufferCapacity,
+                         EventType etype, Class<?> eventClass, String eventDesc,
+                         String eventName, String moduleName, String... metaData) {
+            this.enabled = enabled;
+            this.eventId = eventId;
+            this.bufferCapacity = bufferCapacity;
+            this.etype = etype;
+            this.eventClass = eventClass;
+            this.eventDesc = eventDesc;
+            this.eventName = eventName;
+            this.moduleName = moduleName;
+            this.moduleEventName = moduleName + "/" + eventName;
+            this.metaData = metaData;
+        }
+
+        public int getEventId() { return eventId; }
+        public boolean isEnabled() { return enabled; }
+        public int getBufferCapacity() { return bufferCapacity; }
+        public EventType getEtype() { return etype; }
+        public String getEventDesc() { return eventDesc; }
+        public String getEventName() { return eventName; }
+        public String getModuleName() { return moduleName; }
+        public String getModuleEventName() { return moduleEventName; }
+        public String[] getMetaData() { return metaData; }
+    }
+
+    //******************
+    //   Global stores
+    //******************
+
+    /**
+     * Event history for a particular event-id is stored in a circular buffer
+     */
+    protected class DebugEventHistory {
+        EventInfo einfo;
+        CircularBuffer<Event> eventBuffer;
+
+        public DebugEventHistory(EventInfo einfo, int capacity) {
+            this.einfo = einfo;
+            this.eventBuffer = new CircularBuffer<Event>(capacity);
+        }
+    }
+
+    /**
+     * Global storage for all event types and their corresponding event buffers.
+     * A particular event type is accessed by directly indexing into the array
+     * with the corresponding event-id.
+     */
+    protected DebugEventHistory[] allEvents =
+                    new DebugEventHistory[MAX_EVENTS];
+
+    /**
+     * Global storage for all event ids registered for a module. The map is indexed
+     * by the module name and event name and returns the event-ids that correspond to the
+     * event types registered by that module (for example module 'linkdiscovery'
+     * may register events that have ids 0 and 1 that correspond to link up/down
+     * events, and receiving malformed LLDP packets, respectively).
+     */
+    protected ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>
+        moduleEvents = new ConcurrentHashMap<String,
+                                ConcurrentHashMap<String, Integer>>();
+
+    /**
+     * A collection of event ids that are currently enabled for logging
+     */
+    protected Set<Integer> currentEvents = Collections.newSetFromMap(
+                                       new ConcurrentHashMap<Integer,Boolean>());
+
+    //******************
+    // Thread local stores
+    //******************
+
+    /**
+     * Thread local storage for events
+     */
+    protected class LocalEventHistory {
+        int nextIndex;
+        int maxCapacity;
+        boolean enabled;
+        ArrayList<Event> eventList;
+
+        public LocalEventHistory(boolean enabled, int maxCapacity) {
+            this.nextIndex = 0;
+            this.maxCapacity = maxCapacity;
+            this.enabled = enabled;
+            this.eventList = new ArrayList<Event>();
+        }
+    }
+
+    /**
+     * Thread local event buffers used for maintaining event history local to
+     * a thread. Eventually this locally maintained information is flushed
+     * into the global event buffers.
+     */
+    protected final ThreadLocal<LocalEventHistory[]> threadlocalEvents =
+            new ThreadLocal<LocalEventHistory[]>() {
+        @Override
+        protected LocalEventHistory[] initialValue() {
+            return new LocalEventHistory[MAX_EVENTS];
+        }
+    };
+
+    /**
+     * Thread local cache for event-ids that are currently active.
+     */
+    protected final ThreadLocal<Set<Integer>> threadlocalCurrentEvents =
+            new ThreadLocal<Set<Integer>>() {
+        @Override
+        protected Set<Integer> initialValue() {
+            return new HashSet<Integer>();
+        }
+    };
+
+    //*******************************
+    //   IEventUpdater
+    //*******************************
+
+    protected class EventUpdaterImpl<T> implements IEventUpdater<T> {
+        private final int eventId;
+
+        public EventUpdaterImpl(int evId) {
+            this.eventId = evId;
+        }
+
+        @Override
+        public void updateEventNoFlush(Object event) {
+            if (!validEventId()) return;
+            updateEvent(eventId, false, event);
+        }
+
+        @Override
+        public void updateEventWithFlush(Object event) {
+            if (!validEventId()) return;
+            updateEvent(eventId, true, event);
+        }
+
+        private boolean validEventId() {
+            if (eventId < 0 || eventId >= MAX_EVENTS) {
+                throw new IllegalStateException();
+            }
+            return true;
+        }
+
+    }
+
+    //*******************************
+    //   IDebugEventService
+    //*******************************
+
+    @Override
+    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
+                                              String eventDescription, EventType et,
+                                              Class<T> eventClass, int bufferCapacity,
+                                              String... metaData) throws MaxEventsRegistered {
+        int eventId = -1;
+        synchronized (eventIdLock) {
+             eventId = Integer.valueOf(eventIdCounter++);
+        }
+        if (eventId > MAX_EVENTS-1) {
+            throw new MaxEventsRegistered();
+        }
+
+        // register event id for moduleName
+        if (!moduleEvents.containsKey(moduleName)) {
+            moduleEvents.put(moduleName, new ConcurrentHashMap<String, Integer>());
+        }
+        if (!moduleEvents.get(moduleName).containsKey(eventName)) {
+            moduleEvents.get(moduleName).put(eventName, new Integer(eventId));
+        } else {
+            int existingEventId = moduleEvents.get(moduleName).get(eventName);
+            log.error("Duplicate event registration for moduleName {} eventName {}",
+                      moduleName, eventName);
+            return new EventUpdaterImpl<T>(existingEventId);
+        }
+
+        // create storage for event-type
+        boolean enabled = (et == EventType.ALWAYS_LOG) ? true : false;
+        EventInfo ei = new EventInfo(eventId, enabled, bufferCapacity,
+                                     et, eventClass, eventDescription, eventName,
+                                     moduleName, metaData);
+        allEvents[eventId] = new DebugEventHistory(ei, bufferCapacity);
+        if (enabled) {
+            currentEvents.add(eventId);
+        }
+
+        return new EventUpdaterImpl<T>(eventId);
+    }
+
+    private void updateEvent(int eventId, boolean flushNow, Object eventData) {
+        if (eventId < 0 || eventId > MAX_EVENTS-1) return;
+
+        LocalEventHistory[] thishist = this.threadlocalEvents.get();
+        if (thishist[eventId] == null) {
+            // seeing this event for the first time in this thread - create local
+            // store by consulting global store
+            DebugEventHistory de = allEvents[eventId];
+            if (de != null) {
+                boolean enabled = de.einfo.enabled;
+                int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP/ 100;
+                if (localCapacity < 10)  localCapacity = MIN_LOCAL_CAPACITY;
+                thishist[eventId] = new LocalEventHistory(enabled, localCapacity);
+                if (enabled) {
+                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+                    thisset.add(eventId);
+                }
+            } else {
+                log.error("updateEvent seen locally for event {} but no global"
+                          + "storage exists for it yet .. not updating", eventId);
+                return;
+            }
+        }
+
+        // update local store if enabled locally for updating
+        LocalEventHistory le = thishist[eventId];
+        if (le.enabled) {
+            long timestamp = System.currentTimeMillis();
+            long thisthread = Thread.currentThread().getId();
+            String thisthreadname = Thread.currentThread().getName();
+            if (le.nextIndex < le.eventList.size()) {
+                if (le.eventList.get(le.nextIndex) == null) {
+                    le.eventList.set(le.nextIndex, new Event(timestamp, thisthread,
+                                                             thisthreadname,
+                                                             eventData));
+                } else {
+                    Event e = le.eventList.get(le.nextIndex);
+                    e.timestamp = timestamp;
+                    e.threadId = thisthread;
+                    e.threadName = thisthreadname;
+                    e.eventData = eventData;
+                    e.nullifyCachedFormattedEvent();
+                }
+            } else {
+                le.eventList.add(new Event(timestamp, thisthread, thisthreadname, eventData));
+            }
+            le.nextIndex++;
+
+            if (le.nextIndex >= le.maxCapacity || flushNow) {
+                // flush this buffer now
+                DebugEventHistory de = allEvents[eventId];
+                if (de.einfo.enabled) {
+                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
+                } else {
+                    // global buffer is disabled - don't flush, disable locally
+                    le.enabled = false;
+                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+                    thisset.remove(eventId);
+                }
+                le.nextIndex = 0;
+            }
+        }
+    }
+
+    @Override
+    public void flushEvents() {
+        LocalEventHistory[] thishist = this.threadlocalEvents.get();
+        Set<Integer> thisset = this.threadlocalCurrentEvents.get();
+        ArrayList<Integer> temp = new ArrayList<Integer>();
+
+        for (int eventId : thisset) {
+            LocalEventHistory le = thishist[eventId];
+            if (le != null && le.nextIndex > 0) {
+                // flush this buffer now
+                DebugEventHistory de = allEvents[eventId];
+                if (de.einfo.enabled) {
+                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
+                } else {
+                    // global buffer is disabled - don't flush, disable locally
+                    le.enabled = false;
+                    temp.add(eventId);
+                }
+                le.nextIndex = 0;
+            }
+        }
+        for (int eId : temp)
+            thisset.remove(eId);
+
+        // sync thread local currently enabled set of eventIds with global set.
+        Sets.SetView<Integer> sv = Sets.difference(currentEvents, thisset);
+        for (int eventId : sv) {
+            if (thishist[eventId] != null) {
+                thishist[eventId].enabled = true;
+                thisset.add(eventId);
+            }
+        }
+
+    }
+
+    @Override
+    public boolean containsModuleEventName(String moduleName, String eventName) {
+        if (!moduleEvents.containsKey(moduleName)) return false;
+        if (moduleEvents.get(moduleName).containsKey(eventName)) return true;
+        return false;
+    }
+
+    @Override
+    public boolean containsModuleName(String moduleName) {
+        return moduleEvents.containsKey(moduleName);
+    }
+
+    @Override
+    public List<DebugEventInfo> getAllEventHistory() {
+        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
+        for (Map<String, Integer> modev : moduleEvents.values()) {
+            for (int eventId : modev.values()) {
+                DebugEventHistory de = allEvents[eventId];
+                if (de != null) {
+                    List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+                    for (Event e : de.eventBuffer) {
+                        ret.add(e.getFormattedEvent(de.einfo.eventClass,
+                                                    de.einfo.moduleEventName));
+                    }
+                    moduleEventList.add(new DebugEventInfo(de.einfo, ret));
+                }
+            }
+        }
+        return moduleEventList;
+    }
+
+    @Override
+    public List<DebugEventInfo> getModuleEventHistory(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName)) return Collections.emptyList();
+        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
+        for (int eventId : moduleEvents.get(moduleName).values()) {
+            DebugEventHistory de = allEvents[eventId];
+            if (de != null) {
+                List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+                for (Event e : de.eventBuffer) {
+                    ret.add(e.getFormattedEvent(de.einfo.eventClass,
+                                                de.einfo.moduleEventName));
+                }
+                moduleEventList.add(new DebugEventInfo(de.einfo, ret));
+            }
+        }
+        return moduleEventList;
+    }
+
+    @Override
+    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
+                                                int last) {
+        if (!moduleEvents.containsKey(moduleName)) return null;
+        Integer eventId = moduleEvents.get(moduleName).get(eventName);
+        if (eventId == null) return null;
+        DebugEventHistory de = allEvents[eventId];
+        if (de != null) {
+            int num = 1;
+            List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
+            for (Event e : de.eventBuffer) {
+                if (num > last)
+                    break;
+                Map<String, String> temp = e.getFormattedEvent(de.einfo.eventClass,
+                                                               de.einfo.moduleEventName);
+                temp.put("#", String.valueOf(num++));
+                ret.add(temp);
+            }
+            return new DebugEventInfo(de.einfo, ret);
+        }
+        return null;
+    }
+
+    @Override
+    public void resetAllEvents() {
+        for (Map<String, Integer> eventMap : moduleEvents.values()) {
+            for (Integer evId : eventMap.values()) {
+                allEvents[evId].eventBuffer.clear();
+            }
+        }
+    }
+
+    @Override
+    public void resetAllModuleEvents(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName)) return;
+        Map<String, Integer> modEvents = moduleEvents.get(moduleName);
+        for (Integer evId : modEvents.values()) {
+            allEvents[evId].eventBuffer.clear();
+        }
+    }
+
+    @Override
+    public void resetSingleEvent(String moduleName, String eventName) {
+        if (!moduleEvents.containsKey(moduleName)) return;
+        Integer eventId = moduleEvents.get(moduleName).get(eventName);
+        if (eventId == null) return;
+        DebugEventHistory de = allEvents[eventId];
+        if (de != null) {
+            de.eventBuffer.clear();
+        }
+    }
+
+    @Override
+    public List<String> getModuleList() {
+        List<String> el = new ArrayList<String>();
+        el.addAll(moduleEvents.keySet());
+        return el;
+    }
+
+    @Override
+    public List<String> getModuleEventList(String moduleName) {
+        if (!moduleEvents.containsKey(moduleName))
+            return Collections.emptyList();
+        List<String> el = new ArrayList<String>();
+        el.addAll(moduleEvents.get(moduleName).keySet());
+        return el;
+    }
+
+    //*******************************
+    //   IFloodlightModule
+    //*******************************
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IDebugEventService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+        m.put(IDebugEventService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        ArrayList<Class<? extends IFloodlightService>> deps =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        deps.add(IRestApiService.class);
+        return deps;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        IRestApiService restService =
+                context.getServiceImpl(IRestApiService.class);
+        restService.addRestletRoutable(new DebugEventRoutable());
+        DebugEventAppender.setDebugEventServiceImpl(this);
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java
new file mode 100644
index 0000000..3429675
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java
@@ -0,0 +1,96 @@
+package net.floodlightcontroller.debugevent;
+
+import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
+import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.UnsynchronizedAppenderBase;
+
+public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> {
+    static IDebugEventService debugEvent;
+    static IEventUpdater<WarnErrorEvent> evWarnError;
+    static Thread debugEventRegistryTask = new Thread() {
+        @Override
+        public void run() {
+            while(DebugEventAppender.debugEvent == null) {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    return;
+                }
+            }
+            //safe to register debugEvent
+            registerDebugEventQueue();
+        }
+    };
+
+    @Override
+    public void start() {
+        DebugEventAppender.debugEventRegistryTask.start();
+        super.start();
+    }
+
+    public static void setDebugEventServiceImpl(IDebugEventService debugEvent) {
+        DebugEventAppender.debugEvent = debugEvent;
+        // It is now ok to register an event Q - but letting this thread go
+        // since it was called from a startUp() routine
+    }
+
+    /**
+     * The logging system calls append for every log message. This method filters
+     * out the WARN and ERROR message and adds to a debug event queue that can
+     * be accessed via cli or rest-api or gui.
+     */
+    @Override
+    protected void append(E eventObject) {
+        if (!isStarted()) {
+            return;
+        }
+        if (evWarnError != null) {
+            ILoggingEvent ev = ((ILoggingEvent) eventObject);
+            if (ev.getLevel().equals(Level.ERROR) || ev.getLevel().equals(Level.WARN)) {
+                evWarnError.updateEventWithFlush(
+                      new WarnErrorEvent(ev.getFormattedMessage(), ev.getLevel(),
+                                         ev.getThreadName(), ev.getLoggerName()));
+            }
+        }
+    }
+
+    private static void registerDebugEventQueue() {
+        try {
+            evWarnError = debugEvent.registerEvent("net.floodlightcontroller.core",
+                                     "warn-error-queue",
+                                     "all WARN and ERROR logs",
+                                     EventType.ALWAYS_LOG, WarnErrorEvent.class,
+                                     100);
+        } catch (MaxEventsRegistered e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public static class WarnErrorEvent {
+        @EventColumn(name = "message", description = EventFieldType.STRING)
+        String message;
+
+        @EventColumn(name = "level", description = EventFieldType.OBJECT)
+        Level level;
+
+        @EventColumn(name = "threadName", description = EventFieldType.STRING)
+        String threadName;
+
+        @EventColumn(name = "logger", description = EventFieldType.OBJECT)
+        String logger;
+
+        public WarnErrorEvent(String message, Level level, String threadName,
+                              String logger) {
+            this.message = message;
+            this.level = level;
+            this.threadName = threadName;
+            this.logger = logger;
+        }
+    }
+
+}
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());
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
new file mode 100644
index 0000000..d54e9f6
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
@@ -0,0 +1,189 @@
+package net.floodlightcontroller.debugevent;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugevent.DebugEvent.EventInfo;
+
+public interface IDebugEventService extends IFloodlightService {
+
+    /**
+     * Different event types. Events that are meant to be logged on demand
+     * need to be separately enabled/disabled.
+     */
+    public enum EventType {
+        ALWAYS_LOG,
+        LOG_ON_DEMAND
+    }
+
+    /**
+     * Describes the type of field obtained from reflection
+     */
+    enum EventFieldType {
+        DPID, IPv4, MAC, STRING, OBJECT, PRIMITIVE, LIST_IPV4,
+        LIST_ATTACHMENT_POINT, LIST_OBJECT, SREF_LIST_OBJECT, SREF_OBJECT,
+        FLOW_MOD_FLAGS
+    }
+
+    /**
+     * EventColumn is the only annotation given to the fields of the event
+     * when updating an event.
+     */
+    @Target(ElementType.FIELD)
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface EventColumn {
+        String name() default "param";
+        EventFieldType description() default EventFieldType.PRIMITIVE;
+    }
+
+    /**
+     * Debug Event Qualifiers
+     */
+    public static final String EV_MDATA_WARN = "warn";
+    public static final String EV_MDATA_ERROR = "error";
+
+    /**
+     *  A limit on the maximum number of events that can be created
+     */
+    public static final int MAX_EVENTS = 2000;
+
+    /**
+     * Public class for information returned in response to rest API calls.
+     */
+    public class DebugEventInfo {
+        EventInfo eventInfo;
+        List<Map<String,String>> events;
+
+        public DebugEventInfo(EventInfo eventInfo,
+                              List<Map<String, String>> eventHistory) {
+            this.eventInfo = eventInfo;
+            this.events = eventHistory;
+        }
+
+        public EventInfo getEventInfo() {
+            return eventInfo;
+        }
+
+        public List<Map<String,String>> getEvents() {
+            return events;
+        }
+    }
+
+    /**
+    * exception thrown when MAX_EVENTS have been registered
+    */
+    public class MaxEventsRegistered extends Exception {
+        private static final long serialVersionUID = 2609587082227510262L;
+    }
+
+    /**
+     * Register an event for debugging.
+     *
+     * @param moduleName       module registering event eg. linkdiscovery, virtualrouting.
+     * @param eventName        name given to event.
+     * @param eventDescription A descriptive string describing the event.
+     * @param eventType        EventType for this event. On-demand events have to
+     *                         be explicitly enabled using other methods in this API
+     * @param eventClass       A user defined class that annotates the fields
+     *                         with @EventColumn. This class specifies the
+     *                         fields/columns for this event.
+     * @param bufferCapacity   Number of events to store for this event in a circular
+     *                         buffer. Older events will be discarded once the
+     *                         buffer is full.
+     * @param metaData         variable arguments that qualify an event
+     *                         eg. EV_MDATA_WARN, EV_MDATA_ERROR etc. See Debug Event Qualifiers
+     * @return                 IEventUpdater with update methods that can be used to
+     *                         update an event of the given eventClass
+     * @throws MaxEventsRegistered
+     */
+    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
+                                              String eventDescription,
+                                              EventType eventType,
+                                              Class<T> eventClass,
+                                              int bufferCapacity,
+                                              String... metaData)
+                                                      throws MaxEventsRegistered;
+
+    /**
+     * Update the global event stores with values from the thread local stores. This
+     * method is not typically intended for use by any module. It's typical usage is from
+     * floodlight core for events that happen in the packet processing pipeline.
+     * For other rare events, flushEvents should be called.
+     */
+    public void flushEvents();
+
+    /**
+     * Determine if eventName is a registered event for a given moduleName
+     */
+    public boolean containsModuleEventName(String moduleName, String eventName);
+
+    /**
+     * Determine if any events have been registered for module of name moduleName
+     */
+    public boolean containsModuleName(String moduleName);
+
+    /**
+     * Get event history for all events. This call can be expensive as it
+     * formats the event histories for all events.
+     *
+     * @return  a list of all event histories or an empty list if no events have
+     *          been registered
+     */
+    public List<DebugEventInfo> getAllEventHistory();
+
+    /**
+     * Get event history for all events registered for a given moduleName
+     *
+     * @return  a list of all event histories for all events registered for the
+     *          the module or an empty list if there are no events for this module
+     */
+    public List<DebugEventInfo> getModuleEventHistory(String moduleName);
+
+    /**
+     * Get event history for a single event
+     *
+     * @param  moduleName  registered module name
+     * @param  eventName   registered event name for moduleName
+     * @param  last        last X events
+     * @return DebugEventInfo for that event, or null if the moduleEventName
+     *         does not correspond to a registered event.
+     */
+    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName, int last);
+
+    /**
+     * Wipe out all event history for all registered events
+     */
+    public void resetAllEvents();
+
+    /**
+     * Wipe out all event history for all events registered for a specific module
+     *
+     * @param moduleName  registered module name
+     */
+    public void resetAllModuleEvents(String moduleName);
+
+    /**
+     * Wipe out event history for a single event
+     * @param  moduleName  registered module name
+     * @param  eventName   registered event name for moduleName
+     */
+    public void resetSingleEvent(String moduleName, String eventName);
+
+    /**
+     * Retrieve a list of moduleNames registered for debug events or an empty
+     * list if no events have been registered in the system
+     */
+    public List<String> getModuleList();
+
+    /**
+     * Returns a list of all events registered for a specific moduleName
+     * or a empty list
+     */
+    public List<String> getModuleEventList(String moduleName);
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java b/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java
new file mode 100644
index 0000000..7aec38f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java
@@ -0,0 +1,30 @@
+package net.floodlightcontroller.debugevent;
+
+/**
+ * eventUPdater is used to log events for pre-registered events.
+ */
+public interface IEventUpdater<T> {
+
+    /**
+     * Logs the instance of the event thread-locally. Flushing to the global
+     * circular buffer for this event is delayed resulting in better performance.
+     * This method should typically be used by those events that happen in the
+     * packet processing pipeline
+     *
+     * @param event    an instance of the user-defined event of type T
+     */
+    public void updateEventNoFlush(T event);
+
+    /**
+     * Logs the instance of the event thread-locally and immediated flushes
+     * to the global circular buffer for this event.
+     * This method should typically be used by those events that happen
+     * outside the packet processing pipeline
+     *
+     * @param event    an instance of the user-defined event of type T
+     */
+    public void updateEventWithFlush(T event);
+
+
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java
new file mode 100644
index 0000000..7d479ea
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java
@@ -0,0 +1,135 @@
+package net.floodlightcontroller.debugevent;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
+
+
+    @Override
+    public void flushEvents() {
+
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> services =
+                new ArrayList<Class<? extends IFloodlightService>>(1);
+        services.add(IDebugEventService.class);
+        return services;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+            getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,
+        IFloodlightService> m =
+            new HashMap<Class<? extends IFloodlightService>,
+                IFloodlightService>();
+        m.put(IDebugEventService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        return null;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+
+    }
+
+    @Override
+    public boolean containsModuleEventName(String moduleName, String eventName) {
+        return false;
+    }
+
+    @Override
+    public boolean containsModuleName(String moduleName) {
+        return false;
+    }
+
+    @Override
+    public List<DebugEventInfo> getAllEventHistory() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<DebugEventInfo> getModuleEventHistory(String param) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
+                                                int last) {
+        return null;
+    }
+
+    @Override
+    public void resetAllEvents() {
+
+    }
+
+    @Override
+    public void resetAllModuleEvents(String moduleName) {
+
+    }
+
+    @Override
+    public void resetSingleEvent(String moduleName, String eventName) {
+
+    }
+
+    @Override
+    public <T> IEventUpdater<T>
+            registerEvent(String moduleName, String eventName,
+                          String eventDescription, EventType eventType,
+                          Class<T> eventClass, int bufferCapacity,
+                          String... metaData) throws MaxEventsRegistered {
+        return new NullEventImpl<T>();
+    }
+
+    public class NullEventImpl<T> implements IEventUpdater<T> {
+
+        @Override
+        public void updateEventNoFlush(Object event) {
+
+        }
+
+        @Override
+        public void updateEventWithFlush(Object event) {
+
+        }
+
+    }
+
+    @Override
+    public List<String> getModuleList() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<String> getModuleEventList(String moduleName) {
+        return Collections.emptyList();
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java
new file mode 100644
index 0000000..a3f06ce
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java
@@ -0,0 +1,322 @@
+package net.floodlightcontroller.debugevent.web;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.debugevent.IDebugEventService.DebugEventInfo;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Web interface for Debug Events
+ *
+ * @author Saurav
+ */
+public class DebugEventResource extends DebugEventResourceBase {
+    protected static Logger logger =
+            LoggerFactory.getLogger(DebugEventResource.class);
+
+    /**
+     * The output JSON model that contains the counter information
+     */
+    public static class DebugEventInfoOutput {
+        protected class DEInfo {
+            private final boolean enabled;
+            private final int bufferCapacity;
+            private final EventType eventType;
+            private final String eventDesc;
+            private final String eventName;
+            private final String moduleName;
+            private final String[] metaData;
+            private final List<Map<String,String>> eventHistory;
+
+            DEInfo(DebugEventInfo dei) {
+                this.moduleName = dei.getEventInfo().getModuleName();
+                this.eventName = dei.getEventInfo().getEventName();
+                this.eventDesc = dei.getEventInfo().getEventDesc();
+                this.metaData = dei.getEventInfo().getMetaData();
+                this.enabled = dei.getEventInfo().isEnabled();
+                this.eventType = dei.getEventInfo().getEtype();
+                this.bufferCapacity = dei.getEventInfo().getBufferCapacity();
+                this.eventHistory = dei.getEvents();
+            }
+            public boolean isEnabled() {
+                return enabled;
+            }
+            public int getBufferCapacity() {
+                return bufferCapacity;
+            }
+            public String getEventDesc() {
+                return eventDesc;
+            }
+            public String getEventName() {
+                return eventName;
+            }
+            public String getModuleName() {
+                return moduleName;
+            }
+            public String[] getMetaData() {
+                return metaData;
+            }
+            public EventType getEventType() {
+                return eventType;
+            }
+            public List<Map<String,String>> getEventHistory() {
+                return eventHistory;
+            }
+
+        }
+
+        public Map<String, DEInfo> eventMap = null;
+        public List<String> names = null;
+        public String error = null;
+
+        DebugEventInfoOutput(boolean getList) {
+            if (!getList) {
+                eventMap = new HashMap<String, DEInfo>();
+            }
+        }
+        public Map<String, DEInfo> getEventMap() {
+            return eventMap;
+        }
+        public List<String> getNames() {
+            return names;
+        }
+        public String getError() {
+            return error;
+        }
+
+    }
+
+    public enum Option {
+        ALL, ONE_MODULE, ONE_MODULE_EVENT, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM,
+        ERROR_BAD_MODULE_EVENT_NAME
+    }
+
+    public static class DebugEventPost {
+        public Boolean reset;
+
+        public Boolean getReset() {
+            return reset;
+        }
+        public void setReset(Boolean reset) {
+            this.reset = reset;
+        }
+    }
+
+    public static class ResetOutput {
+        String error = null;
+
+        public String getError() {
+            return error;
+        }
+        public void setError(String error) {
+            this.error = error;
+        }
+    }
+
+    /**
+     * Reset events
+     *
+     * If using curl:
+     * curl -X POST -d {\"reset\":true} -H "Content-Type: application/json" URL
+     * where URL must be in one of the following forms for resetting registered events:
+     * "http://{controller-hostname}:8080/wm/debugevent/
+     * "http://{controller-hostname}:8080/wm/debugevent/{param1}
+     * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
+     *
+     * Not giving {param1} will reset all events
+     * {param1} can be 'all' or the name of a module. The former case will reset
+     * all events, while the latter will reset all events for the moduleName (if
+     * param2 is null).{param2} must be an eventName for the given moduleName to
+     * reset a specific event.
+     */
+    @Post
+    public ResetOutput postHandler(DebugEventPost postData) {
+        ResetOutput output = new ResetOutput();
+        String param1 = (String)getRequestAttributes().get("param1");
+        String param2 = (String)getRequestAttributes().get("param2");
+
+        if (postData.getReset() != null && postData.getReset()) {
+            Option choice = Option.ERROR_BAD_PARAM;
+
+            if (param1 == null) {
+                param1 = "all";
+                choice = Option.ALL;
+            } else if (param1.equals("all")) {
+                choice = Option.ALL;
+            } else if (param2 == null) {
+                boolean isRegistered = debugEvent.containsModuleName(param1);
+                if (isRegistered) {
+                    choice = Option.ONE_MODULE;
+                } else {
+                    choice = Option.ERROR_BAD_MODULE_NAME;
+                }
+            } else {
+                // differentiate between disabled and non-existing events
+                boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
+                if (isRegistered) {
+                    choice = Option.ONE_MODULE_EVENT;
+                } else {
+                    choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
+                }
+            }
+
+            switch (choice) {
+                case ALL:
+                    debugEvent.resetAllEvents();
+                    break;
+                case ONE_MODULE:
+                    debugEvent.resetAllModuleEvents(param1);
+                    break;
+                case ONE_MODULE_EVENT:
+                    debugEvent.resetSingleEvent(param1, param2);
+                    break;
+                case ERROR_BAD_MODULE_NAME:
+                    output.error = "Module name has no corresponding registered events";
+                    break;
+                case ERROR_BAD_MODULE_EVENT_NAME:
+                    output.error = "Event not registered";
+                    break;
+                case ERROR_BAD_PARAM:
+                    output.error = "Bad param";
+            }
+        }
+
+        return output;
+
+    }
+
+    /**
+     * Return the debug event data for the get rest-api call
+     *
+     * URL must be in one of the following forms for retrieving a list
+     * moduleNames    "http://{controller-hostname}:8080/wm/debugevent/
+     * counterNames   "http://{controller-hostname}:8080/wm/debugevent/{moduleName}
+     *
+     * URL must be in one of the following forms for retrieving event data:
+     * "http://{controller-hostname}:8080/wm/debugevent/{param1}
+     * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
+     *
+     *  where {param1} must be one of (no quotes):
+     *       null                   if nothing is given then by default the list
+     *                              of all moduleNames is returned for which
+     *                              events have been registered
+     *       "all"                  can return value/info on all active events
+     *                              but is currently disallowed
+     *       "{moduleName}"         returns value/info on events for the specified module
+     *                              depending on the value of param2
+     *  and   {param2} must be one of (no quotes):
+     *       null                   returns all eventNames registered for the
+     *                              given moduleName (in param1)
+     *       "{eventName}"          returns value/info for specific event if it is active.
+     *
+     */
+    @Get("json")
+    public DebugEventInfoOutput handleEventInfoQuery() {
+        Option choice = Option.ERROR_BAD_PARAM;
+        DebugEventInfoOutput output;
+        String laststr = getQueryValue("last");
+        int last = Integer.MAX_VALUE;
+        try {
+            if (laststr != null)
+                last = Integer.valueOf(laststr);
+            if (last < 1) last = Integer.MAX_VALUE;
+        } catch (NumberFormatException e) {
+            output = new DebugEventInfoOutput(false);
+            output.error = "Expected an integer requesting last X events;" +
+                           " received " + laststr;
+            return output;
+        }
+        String param1 = (String)getRequestAttributes().get("param1");
+        String param2 = (String)getRequestAttributes().get("param2");
+
+        if (param1 == null) {
+            output = new DebugEventInfoOutput(true);
+            return listEvents(output);
+        } else if (param1.equals("all")) {
+            output = new DebugEventInfoOutput(false);
+            //populateEvents(debugEvent.getAllEventHistory(), output);
+            output.error = "Cannot retrieve all events - please select a specific event";
+            return output;
+        }
+
+        if (param2 == null) {
+            output = new DebugEventInfoOutput(true);
+            boolean isRegistered = debugEvent.containsModuleName(param1);
+            if (isRegistered) {
+                return listEvents(param1, output);
+            } else {
+                choice = Option.ERROR_BAD_MODULE_NAME;
+            }
+        } else if (param2.equals("all")) {
+            output = new DebugEventInfoOutput(false);
+            //choice = Option.ONE_MODULE;
+            output.error = "Cannot retrieve all events - please select a specific event";
+            return output;
+        } else {
+            // differentiate between disabled and non-existing events
+            boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
+            if (isRegistered) {
+                choice = Option.ONE_MODULE_EVENT;
+            } else {
+                choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
+            }
+        }
+
+        output = new DebugEventInfoOutput(false);
+        switch (choice) {
+            case ONE_MODULE:
+                populateEvents(debugEvent.getModuleEventHistory(param1), output);
+                break;
+            case ONE_MODULE_EVENT:
+                populateSingleEvent(debugEvent.getSingleEventHistory(param1, param2, last),
+                                    output);
+                break;
+            case ERROR_BAD_MODULE_NAME:
+                output.error = "Module name has no corresponding registered events";
+                break;
+            case ERROR_BAD_MODULE_EVENT_NAME:
+                output.error = "Event not registered";
+                break;
+            case ERROR_BAD_PARAM:
+            default:
+                output.error = "Bad param";
+        }
+
+        return output;
+    }
+
+    private DebugEventInfoOutput listEvents(DebugEventInfoOutput output) {
+        output.names = debugEvent.getModuleList();
+        return output;
+    }
+
+    private DebugEventInfoOutput listEvents(String moduleName,
+                                            DebugEventInfoOutput output) {
+        output.names = debugEvent.getModuleEventList(moduleName);
+        return output;
+    }
+
+    private void populateSingleEvent(DebugEventInfo singleEventHistory,
+                                     DebugEventInfoOutput output) {
+        if (singleEventHistory != null) {
+            output.eventMap.put(singleEventHistory.getEventInfo().getModuleEventName(),
+                                output.new DEInfo(singleEventHistory));
+        }
+    }
+
+    private void populateEvents(List<DebugEventInfo> eventHistory,
+                                DebugEventInfoOutput output) {
+        if (eventHistory != null) {
+            for (DebugEventInfo de : eventHistory)
+                populateSingleEvent(de, output);
+        }
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java
new file mode 100644
index 0000000..964deeb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java
@@ -0,0 +1,18 @@
+package net.floodlightcontroller.debugevent.web;
+
+
+import net.floodlightcontroller.debugevent.IDebugEventService;
+
+import org.restlet.resource.ResourceException;
+import org.restlet.resource.ServerResource;
+
+public class DebugEventResourceBase extends ServerResource{
+    protected IDebugEventService debugEvent;
+
+    @Override
+    protected void doInit() throws ResourceException {
+        super.doInit();
+        debugEvent = (IDebugEventService)getContext().getAttributes().
+                get(IDebugEventService.class.getCanonicalName());
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java
new file mode 100644
index 0000000..d4ee7c6
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java
@@ -0,0 +1,27 @@
+package net.floodlightcontroller.debugevent.web;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+public class DebugEventRoutable implements RestletRoutable {
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("/{param1}/{param2}/", DebugEventResource.class);
+        router.attach("/{param1}/{param2}", DebugEventResource.class);
+        router.attach("/{param1}/", DebugEventResource.class);
+        router.attach("/{param1}", DebugEventResource.class);
+        router.attach("/", DebugEventResource.class);
+        return router;
+    }
+
+    @Override
+    public String basePath() {
+        return "/wm/debugevent";
+    }
+
+}