l3 support (partial): move event dispatch from southBoundHandler 54/10154/8
authorFlavio Fernandes <ffernand@redhat.com>
Fri, 22 Aug 2014 05:27:55 +0000 (01:27 -0400)
committerFlavio Fernandes <ffernand@redhat.com>
Wed, 27 Aug 2014 11:44:32 +0000 (07:44 -0400)
The event handling in southbound needs to move to a common location, so
neutron callbacks can also be enqueued. With these changes, we can now
create a nothBoundHandler, which will take neutron events and enqueue
envents to a shared dispatcher.

Patch set 3: Added copyright headers for the newly added files.
Patch set 4: Make neutron port handler use event dispatcher.
Patch set 5: Fix link to test log
Patch set 6: Use OSGI whiteboard pattern to register event handlers with the dispatcher.
Patch set 7: Code review changes.

Script for creating coke tenants in devstack:
https://gist.github.com/1ba897e7cde8dbd87fe8

Starting odl command:
./run.sh -virt ovsdb -Xms40m -Xmx1024m -XX:MaxPermSize=1024m

LogLevel:
setLogLevel org.opendaylight.ovsdb.openstack.netvirt.providers.OF13Provider trace
setLogLevel org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher trace
setLogLevel org.opendaylight.ovsdb.openstack.netvirt.SouthboundHandler debug
setLogLevel org.opendaylight.ovsdb.openstack.netvirt.PortHandler debug

Log of test:
createTenants: https://gist.github.com/44b4ec87f3c89fe5683e
osgi: https://gist.github.com/47627762ed9d9b474b29

Change-Id: Ieaf8a91e65f82c37ac5fddd2ec824311cd1d5771
Signed-off-by: Flavio Fernandes <ffernand@redhat.com>
15 files changed:
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/AbstractEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/AbstractHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/Activator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/FloatingIPHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NetworkHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NorthboundEvent.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/PortHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/PortSecurityHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/RouterHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundEvent.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SubnetHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/Constants.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EventDispatcher.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/EventDispatcherImpl.java [new file with mode: 0644]

diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/AbstractEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/AbstractEvent.java
new file mode 100644 (file)
index 0000000..28b0afe
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Dave Tucker, Flavio Fernandes
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt;
+
+/**
+ * Abstract class for events used by neutron northbound and southbound events.
+ */
+public abstract class AbstractEvent {
+    public enum HandlerType {
+        SOUTHBOUND,
+        NEUTRON_FLOATING_IP,
+        NEUTRON_NETWORK,
+        NEUTRON_PORT,
+        NEUTRON_PORT_SECURITY,
+        NEUTRON_ROUTER,
+        NEUTRON_SUBNET,
+        NEUTRON_FWAAS;
+
+        public static final int size = HandlerType.values().length;
+    }
+    public enum Action { ADD, UPDATE, DELETE }
+
+    private HandlerType handlerType;
+    private Action action;
+
+    private AbstractEvent() {
+        // this is private to force proper construction
+    }
+
+    protected AbstractEvent(HandlerType handlerType, Action action) {
+        this.handlerType = handlerType;
+        this.action = action;
+    }
+
+    public HandlerType getHandlerType() {
+        return handlerType;
+    }
+
+    public Action getAction() {
+        return action;
+    }
+
+    @Override
+    public String toString() {
+        return "AbstractEvent [handlerType=" + handlerType + " action=" + action + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((handlerType == null) ? 0 : handlerType.hashCode());
+        result = prime * result + ((action == null) ? 0 : action.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AbstractEvent other = (AbstractEvent) obj;
+        if (handlerType == null) {
+            if (other.handlerType != null)
+                return false;
+        } else if (!handlerType.equals(other.handlerType))
+            return false;
+        if (action == null) {
+            if (other.action != null)
+                return false;
+        } else if (!action.equals(other.action))
+            return false;
+        return true;
+    }
+}
index 791c9f026740a0aebcc3656b810248be1a20708f..36969bb9dc23b473a5b1d75e5d1a095325e9a6cc 100644 (file)
@@ -11,14 +11,18 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 
+import com.google.common.base.Preconditions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.HttpURLConnection;
 
 /**
- * Abstract class for utility functions used by neutron handlers.
+ * OpenStack related events originate from multiple north callbacks as well as south.
+ * This interface provides a layer of abstraction between the event dispatcher and the
+ * handlers.
  */
 public abstract class AbstractHandler {
 
@@ -27,6 +31,9 @@ public abstract class AbstractHandler {
      */
     static final Logger logger = LoggerFactory.getLogger(AbstractHandler.class);
 
+    // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile EventDispatcher eventDispatcher;
+
     /**
      * Convert failure status returned by the  manager into
      * neutron API service errors.
@@ -57,4 +64,24 @@ public abstract class AbstractHandler {
 
         return result;
     }
+
+    /**
+     * Enqueue the event.
+     *
+     * @param event the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    protected void enqueueEvent(AbstractEvent abstractEvent) {
+        Preconditions.checkNotNull(eventDispatcher);
+        eventDispatcher.enqueueEvent(abstractEvent);
+    }
+
+    /**
+     * Process the event.
+     *
+     * @param event the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    public abstract void processEvent(AbstractEvent abstractEvent);
+
 }
index 84b9c393b8ddab6655ffa0558f8d3507467cd2c8..7cb1101acb714c0bcfe06041922e91b084652428 100644 (file)
@@ -22,12 +22,15 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.opendaylight.controller.switchmanager.IInventoryListener;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.VlanConfigurationCache;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.BridgeConfigurationManagerImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.ConfigurationServiceImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.EventDispatcherImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.ProviderNetworkManagerImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.TenantNetworkManagerImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.VlanConfigurationCacheImpl;
@@ -37,6 +40,8 @@ import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
 
 import org.apache.felix.dm.Component;
 
+import java.util.Properties;
+
 /**
  * OSGi bundle activator for the OVSDB Neutron Interface.
  */
@@ -80,7 +85,8 @@ public class Activator extends ComponentActivatorAbstractBase {
                         RouterHandler.class,
                         SouthboundHandler.class,
                         PortSecurityHandler.class,
-                        ProviderNetworkManagerImpl.class};
+                        ProviderNetworkManagerImpl.class,
+                        EventDispatcherImpl.class};
         return res;
     }
 
@@ -134,14 +140,25 @@ public class Activator extends ComponentActivatorAbstractBase {
         }
 
         if (imp.equals(FloatingIPHandler.class)) {
-            c.setInterface(INeutronFloatingIPAware.class.getName(), null);
+            Properties floatingIPHandlerPorperties = new Properties();
+            floatingIPHandlerPorperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
+                                            AbstractEvent.HandlerType.NEUTRON_FLOATING_IP);
+            c.setInterface(new String[] {INeutronFloatingIPAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           floatingIPHandlerPorperties);
             c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbInventoryListener.class).setRequired(true));
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(NetworkHandler.class)) {
-            c.setInterface(INeutronNetworkAware.class.getName(), null);
+            Properties networkHandlerProperties = new Properties();
+            networkHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
+                                         AbstractEvent.HandlerType.NEUTRON_NETWORK);
+            c.setInterface(new String[] {INeutronNetworkAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           networkHandlerProperties);
             c.add(createServiceDependency().setService(TenantNetworkManager.class).setRequired(true));
             c.add(createServiceDependency().setService(BridgeConfigurationManager.class).setRequired(true));
             c.add(createServiceDependency().setService(
@@ -150,29 +167,49 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(INeutronNetworkCRUD.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbInventoryListener.class).setRequired(true));
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(SubnetHandler.class)) {
-            c.setInterface(INeutronSubnetAware.class.getName(), null);
+            Properties subnetHandlerProperties = new Properties();
+            subnetHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY, AbstractEvent.HandlerType.NEUTRON_SUBNET);
+            c.setInterface(new String[] {INeutronSubnetAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           subnetHandlerProperties);
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(PortHandler.class)) {
-            c.setInterface(INeutronPortAware.class.getName(), null);
+            Properties portHandlerProperties = new Properties();
+            portHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY, AbstractEvent.HandlerType.NEUTRON_PORT);
+            c.setInterface(new String[] {INeutronPortAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           portHandlerProperties);
             c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbInventoryListener.class).setRequired(true));
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(RouterHandler.class)) {
-            c.setInterface(INeutronRouterAware.class.getName(), null);
+            Properties routerHandlerProperties = new Properties();
+            routerHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY, AbstractEvent.HandlerType.NEUTRON_ROUTER);
+            c.setInterface(new String[] {INeutronRouterAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           routerHandlerProperties);
             c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbInventoryListener.class).setRequired(true));
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(SouthboundHandler.class)) {
+            Properties southboundHandlerProperties = new Properties();
+            southboundHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY, AbstractEvent.HandlerType.SOUTHBOUND);
             c.setInterface(new String[] {OvsdbInventoryListener.class.getName(),
-                                         IInventoryListener.class.getName()}, null);
+                                         IInventoryListener.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           southboundHandlerProperties);
             c.add(createServiceDependency().setService(
                     org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(BridgeConfigurationManager.class).setRequired(true));
@@ -180,11 +217,18 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency().setService(NetworkingProviderManager.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(PortSecurityHandler.class)) {
+            Properties portSecurityHandlerProperties = new Properties();
+            portSecurityHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
+                                              AbstractEvent.HandlerType.NEUTRON_PORT_SECURITY);
             c.setInterface(new String[] {INeutronSecurityRuleAware.class.getName(),
-                                         INeutronSecurityGroupAware.class.getName()}, null);
+                                         INeutronSecurityGroupAware.class.getName(),
+                                         AbstractHandler.class.getName()},
+                           portSecurityHandlerProperties);
+            c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
         }
 
         if (imp.equals(ProviderNetworkManagerImpl.class)) {
@@ -196,5 +240,12 @@ public class Activator extends ComponentActivatorAbstractBase {
                     .setService(NetworkingProvider.class)
                     .setCallbacks("providerAdded", "providerRemoved"));
         }
+
+        if (imp.equals(EventDispatcherImpl.class)) {
+            c.setInterface(EventDispatcher.class.getName(), null);
+            c.add(createServiceDependency()
+                          .setService(AbstractHandler.class)
+                          .setCallbacks("eventHandlerAdded", "eventHandlerRemoved"));
+        }
     }
 }
index e06fbcfaf062955187f6d43ad615fe8e9c0bfec8..f04338e460679ca4ebecb8270468c3e1c747eaaa 100644 (file)
@@ -31,6 +31,7 @@ public class FloatingIPHandler extends AbstractHandler
      */
     static final Logger logger = LoggerFactory.getLogger(FloatingIPHandler.class);
 
+    // The implementation for each of these services is resolved by the OSGi Service Manager
     private volatile OvsdbConfigurationService ovsdbConfigurationService;
     private volatile OvsdbConnectionService connectionService;
     private volatile OvsdbInventoryListener ovsdbInventoryListener;
@@ -122,4 +123,26 @@ public class FloatingIPHandler extends AbstractHandler
                      floatingIP.getFixedIPAddress(),
                      floatingIP.getFloatingIPUUID());
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
 }
index d4b3d4d2c44bdc4f6cdcdbea4b76bc0649976023..32dbabc8f2bf112d9f73c452aa01dceb6ce4f99f 100644 (file)
@@ -194,4 +194,27 @@ public class NetworkHandler extends AbstractHandler
         }
         tenantNetworkManager.networkDeleted(network.getID());
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
+
 }
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NorthboundEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NorthboundEvent.java
new file mode 100644 (file)
index 0000000..d38b93a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Dave Tucker, Flavio Fernandes
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+
+public class NorthboundEvent extends AbstractEvent {
+
+    private NeutronPort port;
+
+    NorthboundEvent(NeutronPort port, Action action) {
+        super(HandlerType.NEUTRON_PORT, action);
+        this.port = port;
+    }
+
+    public NeutronPort getPort() {
+        return port;
+    }
+
+    @Override
+    public String toString() {
+        return "NorthboundEvent [action=" + super.getAction() + ", port=" + port + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((port == null) ? 0 : port.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+        NorthboundEvent other = (NorthboundEvent) obj;
+        if (port == null) {
+            if (other.port != null)
+                return false;
+        } else if (!port.equals(other.port))
+            return false;
+        return true;
+    }
+}
index fa93f1106ecb1521a2ea896197781bb79918875c..0675a34b01cf7d292b5f85bea3756b01704174fd 100644 (file)
@@ -40,6 +40,7 @@ public class PortHandler extends AbstractHandler
      */
     static final Logger logger = LoggerFactory.getLogger(PortHandler.class);
 
+    // The implementation for each of these services is resolved by the OSGi Service Manager
     private volatile OvsdbConfigurationService ovsdbConfigurationService;
     private volatile OvsdbConnectionService connectionService;
     private volatile OvsdbInventoryListener ovsdbInventoryListener;
@@ -69,10 +70,13 @@ public class PortHandler extends AbstractHandler
             return;
         }
 
+        enqueueEvent(new NorthboundEvent(port, NorthboundEvent.Action.ADD));
+    }
+    private void doNeutronPortCreated(NeutronPort port) {
         logger.debug(" Port-ADD successful for tenant-id - {}," +
-                     " network-id - {}, port-id - {}, result - {} ",
+                     " network-id - {}, port-id - {}",
                      port.getTenantID(), port.getNetworkUUID(),
-                     port.getID(), result);
+                     port.getID());
     }
 
     /**
@@ -135,6 +139,11 @@ public class PortHandler extends AbstractHandler
             return;
         }
 
+        enqueueEvent(new NorthboundEvent(neutronPort, NorthboundEvent.Action.DELETE));
+    }
+    private void doNeutronPortDeleted(NeutronPort neutronPort) {
+        logger.debug("Handling neutron delete port " + neutronPort);
+
         List<Node> nodes = connectionService.getNodes();
         for (Node node : nodes) {
             try {
@@ -183,4 +192,30 @@ public class PortHandler extends AbstractHandler
                      neutronPort.getID());
 
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case ADD:
+                doNeutronPortCreated(ev.getPort());
+                break;
+            case DELETE:
+                doNeutronPortDeleted(ev.getPort());
+                break;
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
 }
index 829f6a12d1236c944bd2a8bd49e1e690c9ad3f57..26379b4b8b767b6de3b2ac8811e4353f808225b4 100644 (file)
@@ -116,4 +116,27 @@ public class PortSecurityHandler extends AbstractHandler
             return;
         }
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
+
 }
\ No newline at end of file
index cd46ef8c2156577c9a28927f019f0555d2cd6d5f..cf00e17c48849bff02d28aeced73a188fb5da66f 100644 (file)
@@ -32,6 +32,7 @@ public class RouterHandler extends AbstractHandler
      */
     static final Logger logger = LoggerFactory.getLogger(RouterHandler.class);
 
+    // The implementation for each of these services is resolved by the OSGi Service Manager
     private volatile OvsdbConfigurationService ovsdbConfigurationService;
     private volatile OvsdbConnectionService connectionService;
     private volatile OvsdbInventoryListener ovsdbInventoryListener;
@@ -189,4 +190,26 @@ public class RouterHandler extends AbstractHandler
         logger.debug(" Router {} interface {} detached. Subnet {}", router.getName(), routerInterface.getPortUUID(),
                      routerInterface.getSubnetUUID());
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
 }
index ac7b6a13e7ab58ccd6acf77b2a9b2796f71ec83d..1562f8c1c9a036f3a47cbe7f21d14a3603d74332 100644 (file)
@@ -12,35 +12,30 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.ovsdb.lib.notation.Row;
 
-public class SouthboundEvent {
+public class SouthboundEvent extends AbstractEvent {
     public enum Type { NODE, ROW };
-    public enum Action { ADD, UPDATE, DELETE };
     private Type type;
-    private Action action;
     private Node node;
     private String tableName;
     private String uuid;
     private Row row;
     private Object context;
     public SouthboundEvent(Node node, Action action) {
-        super();
+        super(HandlerType.SOUTHBOUND, action);
         this.type = Type.NODE;
-        this.action = action;
         this.node = node;
     }
     public SouthboundEvent(Node node, String tableName, String uuid, Row row, Action action) {
-        super();
+        super(HandlerType.SOUTHBOUND, action);
         this.type = Type.ROW;
-        this.action = action;
         this.node = node;
         this.tableName = tableName;
         this.uuid = uuid;
         this.row = row;
     }
     public SouthboundEvent(Node node, String tableName, String uuid, Row row, Object context, Action action) {
-        super();
+        super(HandlerType.SOUTHBOUND, action);
         this.type = Type.ROW;
-        this.action = action;
         this.node = node;
         this.tableName = tableName;
         this.uuid = uuid;
@@ -50,9 +45,6 @@ public class SouthboundEvent {
     public Type getType() {
         return type;
     }
-    public Action getAction() {
-        return action;
-    }
     public Node getNode() {
         return node;
     }
@@ -70,14 +62,13 @@ public class SouthboundEvent {
     }
     @Override
     public String toString() {
-        return "SouthboundEvent [type=" + type + ", action=" + action + ", node=" + node + ", tableName=" + tableName
+        return "SouthboundEvent [type=" + type + ", action=" + super.getAction() + ", node=" + node + ", tableName=" + tableName
                 + ", uuid=" + uuid + ", row=" + row + ", context=" + context.toString() + "]";
     }
     @Override
     public int hashCode() {
         final int prime = 31;
-        int result = 1;
-        result = prime * result + ((action == null) ? 0 : action.hashCode());
+        int result = super.hashCode();
         result = prime * result + ((node == null) ? 0 : node.hashCode());
         result = prime * result + ((tableName == null) ? 0 : tableName.hashCode());
         result = prime * result + ((type == null) ? 0 : type.hashCode());
@@ -92,9 +83,9 @@ public class SouthboundEvent {
             return false;
         if (getClass() != obj.getClass())
             return false;
-        SouthboundEvent other = (SouthboundEvent) obj;
-        if (action != other.action)
+        if (!super.equals(obj))
             return false;
+        SouthboundEvent other = (SouthboundEvent) obj;
         if (node == null) {
             if (other.node != null)
                 return false;
@@ -105,7 +96,10 @@ public class SouthboundEvent {
                 return false;
         } else if (!tableName.equals(other.tableName))
             return false;
-        if (type != other.type)
+        if (type == null) {
+            if (other.type != null)
+                return false;
+        } else if (!type.equals(other.type))
             return false;
         if (uuid == null) {
             if (other.uuid != null)
index 16ffc9db5900416f66a8709df4811a2d910a8ca4..947d58a0712e8ade6cf05581bbd338d23558f67a 100644 (file)
@@ -35,18 +35,12 @@ import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
 
-public class SouthboundHandler extends AbstractHandler implements OvsdbInventoryListener, IInventoryListener {
+public class SouthboundHandler extends AbstractHandler implements OvsdbInventoryListener,
+                                                                  IInventoryListener {
     static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class);
     //private Thread eventThread;
-    private ExecutorService eventHandler;
-    private BlockingQueue<SouthboundEvent> events;
     List<Node> nodeCache;
 
     // The implementation for each of these services is resolved by the OSGi Service Manager
@@ -58,67 +52,13 @@ public class SouthboundHandler extends AbstractHandler implements OvsdbInventory
     private volatile OvsdbConnectionService connectionService;
 
     void init() {
-        eventHandler = Executors.newSingleThreadExecutor();
-        this.events = new LinkedBlockingQueue<>();
         nodeCache = Lists.newArrayList();
     }
 
     void start() {
-        eventHandler.submit(new Runnable()  {
-            @Override
-            public void run() {
-                while (true) {
-                    SouthboundEvent ev;
-                    try {
-                        ev = events.take();
-                    } catch (InterruptedException e) {
-                        logger.info("The event handler thread was interrupted, shutting down", e);
-                        return;
-                    }
-                    switch (ev.getType()) {
-                    case NODE:
-                        try {
-                            processNodeUpdate(ev.getNode(), ev.getAction());
-                        } catch (Exception e) {
-                            logger.error("Exception caught in ProcessNodeUpdate for node " + ev.getNode(), e);
-                        }
-                        break;
-                    case ROW:
-                        try {
-                            processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(),
-                                             ev.getContext(),ev.getAction());
-                        } catch (Exception e) {
-                            logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e);
-                        }
-                        break;
-                    default:
-                        logger.warn("Unable to process action " + ev.getAction() + " for node " + ev.getNode());
-                    }
-                }
-            }
-        });
         this.triggerUpdates();
     }
 
-    void stop() {
-        // stop accepting new tasks
-        eventHandler.shutdown();
-        try {
-            // Wait a while for existing tasks to terminate
-            if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
-                eventHandler.shutdownNow();
-                // Wait a while for tasks to respond to being cancelled
-                if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS))
-                    logger.error("Southbound Event Handler did not terminate");
-            }
-        } catch (InterruptedException e) {
-            // (Re-)Cancel if current thread also interrupted
-            eventHandler.shutdownNow();
-            // Preserve interrupt status
-            Thread.currentThread().interrupt();
-        }
-    }
-
     @Override
     public void nodeAdded(Node node, InetAddress address, int port) {
         this.enqueueEvent(new SouthboundEvent(node, SouthboundEvent.Action.ADD));
@@ -142,7 +82,7 @@ public class SouthboundHandler extends AbstractHandler implements OvsdbInventory
     }
 
     /*
-     * Ignore unneccesary updates to be even considered for processing.
+     * Ignore unnecessary updates to be even considered for processing.
      * (Especially stats update are fast and furious).
      */
 
@@ -180,14 +120,6 @@ public class SouthboundHandler extends AbstractHandler implements OvsdbInventory
         this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, context, SouthboundEvent.Action.DELETE));
     }
 
-    private void enqueueEvent (SouthboundEvent event) {
-        try {
-            events.put(event);
-        } catch (InterruptedException e) {
-            logger.error("Thread was interrupted while trying to enqueue event ", e);
-        }
-    }
-
     public void processNodeUpdate(Node node, SouthboundEvent.Action action) {
         if (action == SouthboundEvent.Action.DELETE) return;
         logger.trace("Process Node added {}", node);
@@ -394,4 +326,40 @@ public class SouthboundHandler extends AbstractHandler implements OvsdbInventory
             }
         }
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof SouthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        SouthboundEvent ev = (SouthboundEvent) abstractEvent;
+        switch (ev.getType()) {
+            case NODE:
+                try {
+                    processNodeUpdate(ev.getNode(), ev.getAction());
+                } catch (Exception e) {
+                    logger.error("Exception caught in ProcessNodeUpdate for node " + ev.getNode(), e);
+                }
+                break;
+            case ROW:
+                try {
+                    processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(),
+                                     ev.getContext(),ev.getAction());
+                } catch (Exception e) {
+                    logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e);
+                }
+                break;
+            default:
+                logger.warn("Unable to process type " + ev.getType() +
+                            " action " + ev.getAction() + " for node " + ev.getNode());
+                break;
+        }
+    }
 }
index 82ce662f31f30781d8c00a6a3c46f40de3a12ca8..6fd50ad90290b7364a73b59ad0169fd6558ef551 100644 (file)
@@ -54,4 +54,26 @@ public class SubnetHandler extends AbstractHandler implements INeutronSubnetAwar
         // TODO Auto-generated method stub
 
     }
+
+    /**
+     * Process the event.
+     *
+     * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     */
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NorthboundEvent)) {
+            logger.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NorthboundEvent ev = (NorthboundEvent) abstractEvent;
+        switch (ev.getAction()) {
+            // TODO: add handling of events here, once callbacks do something
+            //       other than logging.
+            default:
+                logger.warn("Unable to process event action " + ev.getAction());
+                break;
+        }
+    }
 }
index a6b66457dcfa36ab622c2e3ddd94f8ce116f142a..7741f61c04162765c9328f9982da91314aebf5de 100644 (file)
@@ -59,4 +59,5 @@ public final class Constants {
     public static final String SOUTHBOUND_PROTOCOL_PROPERTY = "southboundProtocol";
     public static final String PROVIDER_TYPE_PROPERTY = "providerType";
     public static final String OPENFLOW_VERSION_PROPERTY = "openflowVersion";
+    public static final String EVENT_HANDLER_TYPE_PROPERTY = "eventHandlerType";
 }
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EventDispatcher.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EventDispatcher.java
new file mode 100644 (file)
index 0000000..c399a42
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Dave Tucker, Flavio Fernandes
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.api;
+
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent;
+
+/**
+ * Openstack related events will be enqueued into a common event queue.
+ * This interface provides access to an event dispatcher, as well as registration to link dispatcher to which handlers
+ * dispatcher will utilize.
+ */
+public interface EventDispatcher {
+    /**
+     * Enqueue the event.
+     * @param event the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     */
+    public void enqueueEvent(AbstractEvent event);
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/EventDispatcherImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/EventDispatcherImpl.java
new file mode 100644 (file)
index 0000000..b14daea
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Dave Tucker, Flavio Fernandes
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.impl;
+
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent;
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractHandler;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
+
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class EventDispatcherImpl implements EventDispatcher {
+
+    static final Logger logger = LoggerFactory.getLogger(EventDispatcher.class);
+    private ExecutorService eventHandler;
+    private BlockingQueue<AbstractEvent> events;
+
+    private AbstractHandler[] handlers;
+
+    void init() {
+        eventHandler = Executors.newSingleThreadExecutor();
+        this.events = new LinkedBlockingQueue<>();
+        this.handlers = new AbstractHandler[AbstractEvent.HandlerType.size];
+    }
+
+    void start() {
+        eventHandler.submit(new Runnable()  {
+            @Override
+            public void run() {
+                while (true) {
+                    AbstractEvent ev;
+                    try {
+                        ev = events.take();
+                    } catch (InterruptedException e) {
+                        logger.info("The event handler thread was interrupted, shutting down", e);
+                        return;
+                    }
+                    dispatchEvent(ev);
+                }
+            }
+        });
+        logger.debug("event dispatcher is started");
+    }
+
+    void stop() {
+        // stop accepting new tasks
+        eventHandler.shutdown();
+        try {
+            // Wait a while for existing tasks to terminate
+            if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
+                eventHandler.shutdownNow();
+                // Wait a while for tasks to respond to being cancelled
+                if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS))
+                    logger.error("Dispatcher's event handler did not terminate");
+            }
+        } catch (InterruptedException e) {
+            // (Re-)Cancel if current thread also interrupted
+            eventHandler.shutdownNow();
+            // Preserve interrupt status
+            Thread.currentThread().interrupt();
+        }
+        logger.debug("event dispatcher is stopped");
+    }
+
+    private void dispatchEvent(AbstractEvent ev) {
+        AbstractHandler handler = handlers[ev.getHandlerType().ordinal()];
+        if (handler == null) {
+            logger.warn("event dispatcher found no handler for " + ev);
+            return;
+        }
+
+        handler.processEvent(ev);
+    }
+
+    public void eventHandlerAdded(final ServiceReference ref, AbstractHandler handler){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        Object handlerTypeObject = ref.getProperty(Constants.EVENT_HANDLER_TYPE_PROPERTY);
+        if (!(handlerTypeObject instanceof AbstractEvent.HandlerType)){
+            logger.error("Abstract handler reg failed to provide a valid handler type " + handlerTypeObject);
+            return;
+        }
+        AbstractEvent.HandlerType handlerType = (AbstractEvent.HandlerType) handlerTypeObject;
+        handlers[handlerType.ordinal()] = handler;
+
+        logger.debug("Event handler for type {} registered for {}, pid {}",
+                     handlerType, handler.getClass().getName(), pid);
+    }
+
+    public void eventHandlerRemoved(final ServiceReference ref){
+        Long pid = (Long) ref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        Object handlerTypeObject = ref.getProperty(Constants.EVENT_HANDLER_TYPE_PROPERTY);
+        if (!(handlerTypeObject instanceof AbstractEvent.HandlerType)){
+            logger.error("Abstract handler unreg failed to provide a valid handler type " + handlerTypeObject);
+            return;
+        }
+        AbstractEvent.HandlerType handlerType = (AbstractEvent.HandlerType) handlerTypeObject;
+        handlers[handlerType.ordinal()] = null;
+
+        logger.debug("Event handler for type {} unregistered pid {}", handlerType, pid);
+    }
+
+    /**
+     * Enqueue the event.
+     *
+     * @param event the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
+     */
+    @Override
+    public void enqueueEvent(AbstractEvent event) {
+        if (event == null) {
+            return;
+        }
+
+        try {
+            events.put(event);
+        } catch (InterruptedException e) {
+            logger.error("Thread was interrupted while trying to enqueue event ", e);
+        }
+    }
+}