changed the pom.xml to include proper integration test 55/2755/3
authorBasheeruddin Ahmed <syedbahm@cisco.com>
Thu, 14 Nov 2013 20:03:54 +0000 (12:03 -0800)
committerBasheeruddin Ahmed <syedbahm@cisco.com>
Mon, 18 Nov 2013 15:07:35 +0000 (07:07 -0800)
Change-Id: I644e3c66ca16979dbb1a3f0b50e3ae9729265a03
Signed-off-by: Basheeruddin Ahmed <syedbahm@cisco.com>
12 files changed:
opendaylight/md-sal/pom.xml
opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java with 52% similarity]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java with 69% similarity]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml [new file with mode: 0644]

index 3198109..d6e966a 100644 (file)
@@ -48,7 +48,7 @@
         <module>statistics-manager</module>
         <!-- Compability Packages -->
         <module>compatibility</module>
-
+        <module>zeromq-routingtable/implementation</module>
         <module>sal-zeromq-connector</module>
     </modules>
 
@@ -61,6 +61,7 @@
            </activation>
             <modules>
                 <module>sal-binding-it</module>
+                <module>zeromq-routingtable/integrationtest</module>
                 <module>clustered-data-store/integrationtest</module>
                 <module>test</module>
             </modules>
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml b/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml
new file mode 100644 (file)
index 0000000..37c973e
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+        <tag>HEAD</tag>
+    </scm>
+
+    <artifactId>zeromq-routingtable.implementation</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+
+                        <Import-Package>
+                            javax.xml.bind.annotation,
+                            org.opendaylight.controller.sal.core,
+                            org.opendaylight.controller.sal.utils,
+                            org.opendaylight.controller.sal.packet,
+                            org.opendaylight.controller.sal.topology,
+                            org.opendaylight.controller.clustering.services,
+                            org.opendaylight.controller.md.sal.common.api.data,
+                            org.opendaylight.yangtools.yang.binding,
+                            org.osgi.service.component,
+                            org.slf4j,
+                            org.apache.felix.dm,
+                            org.apache.commons.lang3.builder,
+                            org.apache.commons.lang3.tuple,
+                            org.eclipse.osgi.framework.console,
+                            org.osgi.framework,
+                            javax.transaction,
+                            com.google.common.base
+                        </Import-Package>
+                        <Bundle-Activator>
+                            org.opendaylight.controller.sal.connector.remoterpc.impl.Activator
+                        </Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-connector-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>clustering.services</artifactId>
+            <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
+
+    </dependencies>
+</project>
@@ -7,13 +7,12 @@
  */
 package org.opendaylight.controller.sal.connector.remoterpc.api;
 
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
 import java.util.EventListener;
 
-public interface RouteChangeListener extends EventListener {
+public interface RouteChangeListener<I,R> extends EventListener {
+
+
+   void onRouteUpdated(I key, R new_value);
 
-  public void onRouteChanged(RouteChange<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>  change);
+   void onRouteDeleted(I key);
 }
@@ -11,6 +11,8 @@ import java.util.Set;
 
 public interface RoutingTable<I,R> {
 
+
+
   /**
    * Adds a network address for the route. If address for route
    * exists, appends the address to the list
@@ -18,17 +20,22 @@ public interface RoutingTable<I,R> {
    * @param routeId route identifier
    * @param route network address
    */
-  public void addRoute(I routeId, R route);
+  public void addRoute(I routeId, R route) throws SystemException,  RoutingTableException;
 
   /**
    * Adds a network address for the route. If the route already exists,
-   * it throws. This method would be used when registering a global service.
+   * it throws <code>DuplicateRouteException</code>.
+   * This method would be used when registering a global service.
+   *
    *
    * @param routeId route identifier
    * @param route network address
    * @throws DuplicateRouteException
    */
-  public void addGlobalRoute(I routeId, R route) throws DuplicateRouteException;
+  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
+
+
+
 
   /**
    * Removes the network address for the route from routing table. If only
@@ -38,6 +45,14 @@ public interface RoutingTable<I,R> {
    */
   public void removeRoute(I routeId, R route);
 
+
+    /**
+     * Remove the route.
+     * This method would be used when registering a global service.
+     * @param routeId
+     */
+    public void removeGlobalRoute(I routeId);
+
   /**
    * Returns a set of network addresses associated with this route
    * @param routeId
@@ -49,12 +64,18 @@ public interface RoutingTable<I,R> {
    * Returns only one address from the list of network addresses
    * associated with the route. The algorithm to determine that
    * one address is upto the implementer
-   * @param route
+   * @param routeId
    * @return
    */
   public R getARoute(I routeId);
 
   public void registerRouteChangeListener(RouteChangeListener listener);
 
-  public class DuplicateRouteException extends Exception {}
+  public class DuplicateRouteException extends RoutingTableException {
+      public DuplicateRouteException(String message) {
+          super(message);
+      }
+
+  }
+
 }
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java
new file mode 100644 (file)
index 0000000..fc7f6f1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+package org.opendaylight.controller.sal.connector.remoterpc.api;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableException extends Exception {
+
+    /**
+     * Constructs a new exception with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public RoutingTableException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public RoutingTableException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     */
+    public RoutingTableException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java
new file mode 100644 (file)
index 0000000..491858e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+
+
+
+package org.opendaylight.controller.sal.connector.remoterpc.api;
+
+/**
+ * @author: syedbahm
+ *
+ */
+public class SystemException extends  Exception {
+    /**
+     * Constructs a new exception with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public SystemException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public SystemException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public SystemException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java
new file mode 100644 (file)
index 0000000..4541443
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+/**
+ * @author: syedbahm
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+    private static final String CACHE_UPDATE_AWARE_REGISTRY_KEY = "cachenames" ;
+
+
+    /**
+     * Method which tells how many Global implementations are
+     * supported by the bundle. This way we can tune the number of
+     * components created. This components will be created ONLY at the
+     * time of bundle startup and will be destroyed only at time of
+     * bundle destruction, this is the major difference with the
+     * implementation retrieved via getImplementations where all of
+     * them are assumed to be in a container!
+     *
+     *
+     * @return The list of implementations the bundle will support,
+     * in Global version
+     */
+
+    @Override
+    protected Object[] getGlobalImplementations(){
+        logger.debug("Calling getGlobalImplementations to return:", RoutingTableImpl.class);
+        return new Object[] {
+                RoutingTableImpl.class
+        };
+    }
+
+    /**
+     * Configure the dependency for a given instance Global
+     *
+     * @param c Component assigned for this instance, this will be
+     * what will be used for configuration
+     * @param imp implementation to be configured
+     *
+     */
+    @Override
+    protected void configureGlobalInstance(Component c, Object imp){
+        if (imp.equals(RoutingTableImpl.class)) {
+            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
+            Set<String> propSet = new HashSet<String>();
+            propSet.add(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE);
+            props.put(CACHE_UPDATE_AWARE_REGISTRY_KEY, propSet);
+
+            c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName()  }, props);
+            logger.debug("configureGlobalInstance adding dependency:", IClusterGlobalServices.class);
+
+            c.add(createServiceDependency().setService(
+                    IClusterGlobalServices.class).setCallbacks(
+                    "setClusterGlobalServices",
+                    "unsetClusterGlobalServices").setRequired(true));
+
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java
new file mode 100644 (file)
index 0000000..558c8a8
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import com.google.common.base.Preconditions;
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.*;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import java.util.*;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableImpl<I, R> implements RoutingTable<I, R>,ICacheUpdateAware<I,R> {
+    public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
+
+  private Logger log = LoggerFactory
+            .getLogger(RoutingTableImpl.class);
+
+  private IClusterGlobalServices clusterGlobalServices = null;
+  private RoutingTableImpl routingTableInstance = null;
+  private ConcurrentMap routingTableCache = null;
+  private List<RouteChangeListener>  routeChangeListeners = new ArrayList<RouteChangeListener>();
+  private ServiceRegistration cacheAwareRegistration = null;
+                                                      
+ public RoutingTableImpl() {
+  }
+
+  @Override
+  public void addRoute(I routeId, R route) throws RoutingTableException {
+       throw new UnsupportedOperationException(" Not implemented yet!");
+  }
+
+  @Override
+  public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
+    try {
+
+      Set<R> existingRoute = null;
+      // ok does the global route is already registered ?
+      if ((existingRoute = getRoutes(routeId)) == null) {
+
+          if(log.isDebugEnabled()){
+              log.debug("addGlobalRoute: adding  a new route with id"+ routeId + " and value = "+route);
+          }
+        // lets start a transaction
+        clusterGlobalServices.tbegin();
+        Set<R> routes  = new HashSet<R>();
+        routes.add(route);
+        routingTableCache.put(routeId, routes);
+        clusterGlobalServices.tcommit();
+      } else {
+        throw new DuplicateRouteException(" There is already existing route " + existingRoute);
+      }
+
+    } catch (NotSupportedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (HeuristicRollbackException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (RollbackException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (javax.transaction.SystemException e){
+        throw new SystemException ( "System error occurred - while trying to create with value",e);
+    }
+
+  }
+
+  @Override
+  public void removeRoute(I routeId, R route) {
+         throw new UnsupportedOperationException("Not implemented yet!");
+  }
+    @Override
+    public void removeGlobalRoute(I routeId) {
+        routingTableCache.remove(routeId);
+    }
+
+  @Override
+  public Set<R> getRoutes(I routeId) {
+
+      //Note: currently works for global routes only wherein there is just single route
+      Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
+      return (Set<R>) routingTableCache.get(routeId);
+  }
+
+  @Override
+  public R getARoute(I routeId) {
+       throw new UnsupportedOperationException("Not implemented yet!");
+  }
+
+  /**
+   * Registers listener for sending any change notification
+   * 
+   * @param listener
+   */
+  @Override
+  public void registerRouteChangeListener(RouteChangeListener listener) {
+      routeChangeListeners.add(listener);
+  }
+
+
+    /**
+     * Returning the list of route change listeners for Unit testing
+     * Note: the package scope is default
+     * @return   List of registered RouteChangeListener<I,R> listeners
+     */
+  List<RouteChangeListener> getRegisteredRouteChangeListeners(){
+      return routeChangeListeners;
+  }
+
+  public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    this.clusterGlobalServices = clusterGlobalServices;
+  }
+
+  public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    if(cacheAwareRegistration != null) {
+        cacheAwareRegistration.unregister();
+    }
+    this.clusterGlobalServices = null;
+  }
+
+    /**
+     * Creates the Routing Table clustered global services cache
+     * @throws CacheExistException  -- cluster global services exception when cache exist
+     * @throws CacheConfigException -- cluster global services exception during cache config
+     * @throws CacheListenerAddException  -- cluster global services exception during adding of listener
+     */
+
+  void createRoutingTableCache() throws CacheExistException, CacheConfigException, CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    // let us check here if the cache already exists -- if so don't create
+    if (!clusterGlobalServices.existCache(
+        ROUTING_TABLE_GLOBAL_CACHE)) {
+
+        if(log.isDebugEnabled()){
+            log.debug("createRoutingTableCache: creating a new routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
+        }
+      routingTableCache = clusterGlobalServices.createCache(
+          ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+    } else {
+        if(log.isDebugEnabled()){
+            log.debug("createRoutingTableCache: found existing routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
+        }
+      routingTableCache = clusterGlobalServices.getCache(
+          ROUTING_TABLE_GLOBAL_CACHE);
+    }
+
+  }
+
+  /**
+   * Function called by the dependency manager when all the required
+   * dependencies are satisfied
+   * 
+   */
+  void init(Component c) {
+    try {
+
+      createRoutingTableCache();
+    } catch (CacheExistException e) {
+      throw new IllegalStateException("could not construct routing table cache");
+    } catch (CacheConfigException e) {
+      throw new IllegalStateException("could not construct routing table cache");
+    } catch (CacheListenerAddException e) {
+        throw new IllegalStateException("could not construct routing table cache");
+    }
+  }
+
+
+    /**
+     * Get routing table method is useful for unit testing
+     * <note>It has package scope</note>
+     */
+    ConcurrentMap getRoutingTableCache(){
+        return this.routingTableCache;
+    }
+
+
+      /**
+       * Invoked when a new entry is available in the cache, the key is
+       * only provided, the value will come as an entryUpdate invocation
+       *
+       * @param key         Key for the entry just created
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryCreated(I key, String cacheName, boolean originLocal) {
+          //TBD: do we require this.
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryCreated  routeId = "+key
+                      + " cacheName="+cacheName
+                      );
+          }
+      }
+
+      /**
+       * Called anytime a given entry is updated
+       *
+       * @param key         Key for the entry modified
+       * @param new_value   the new value the key will have
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryUpdated  routeId = "+key
+                      + ",value = "+ new_value
+                      + " ,cacheName="+cacheName
+                      );
+          }
+          for(RouteChangeListener rcl:routeChangeListeners){
+              rcl.onRouteUpdated(key, new_value);
+          }
+      }
+
+      /**
+       * Called anytime a given key is removed from the
+       * ConcurrentHashMap we are listening to.
+       *
+       * @param key         Key of the entry removed
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryDeleted(I key, String cacheName, boolean originLocal) {
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryUpdated  routeId = "+key
+                      + " local = "+ originLocal
+                      + " cacheName="+cacheName
+                       );
+          }
+          for(RouteChangeListener rcl:routeChangeListeners){
+              rcl.onRouteDeleted(key);
+          }
+      }
+  }
\ No newline at end of file
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java
new file mode 100644 (file)
index 0000000..75cc6f5
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * 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
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import junit.framework.Assert;
+import org.apache.felix.dm.Component;
+import org.junit.Test;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import java.net.URI;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableImplTest {
+
+    private IClusterGlobalServices ics =  mock(IClusterGlobalServices.class);
+    private RoutingTableImpl rti = new RoutingTableImpl();
+
+    private final URI namespace = URI.create("http://cisco.com/example");
+    private final QName QNAME = new QName(namespace,"global");
+
+    ConcurrentMap concurrentMapMock = mock(ConcurrentMap.class);
+
+
+    @Test
+    public void testAddGlobalRoute() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getType()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal = (Set<String>)latestCache.get(routeIdentifier);
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+    }
+
+    @Test
+    public void testGetRoutes() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getContext()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+
+
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+
+
+    }
+    @Test
+    public void testRegisterRouteChangeListener() throws Exception {
+        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0);
+        rti.registerRouteChangeListener(new RouteChangeListenerImpl());
+
+        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1);
+
+    }
+    @Test
+    public void testRemoveGlobalRoute()throws Exception {
+
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getContext()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+
+
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+        rti.removeGlobalRoute(routeIdentifier);
+
+        Assert.assertNotNull(rti.getRoutes(routeIdentifier));
+
+
+    }
+
+    private ConcurrentMap createRoutingTableCache() throws Exception {
+
+        //here init
+        Component c = mock(Component.class);
+
+        when(ics.existCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(false);
+
+        when(ics.createCache(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(concurrentMapMock);
+         rti.setClusterGlobalServices(this.ics);
+        rti.init(c);
+
+        Assert.assertEquals(concurrentMapMock,rti.getRoutingTableCache() );
+        return concurrentMapMock;
+
+    }
+
+
+    @Test
+    public void testCreateRoutingTableCacheReturnExistingCache() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        //OK here we should try creating again the cache but this time it should return the existing one
+        when(ics.existCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(true);
+
+        when(ics.getCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(concurrentMap);
+
+
+        //here init
+        Component c = mock(Component.class);
+
+        rti.init(c);
+
+        Assert.assertEquals(concurrentMap,rti.getRoutingTableCache());
+
+
+
+
+
+    }
+
+    private class RouteChangeListenerImpl<I,R> implements RouteChangeListener<I,R>{
+
+        @Override
+        public void onRouteUpdated(I key, R new_value) {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        @Override
+        public void onRouteDeleted(I key) {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml b/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml
new file mode 100644 (file)
index 0000000..308d5a9
--- /dev/null
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.integrationtest</artifactId>
+    <version>0.5.1-SNAPSHOT</version>
+    <relativePath>../../../commons/integrationtest</relativePath>
+  </parent>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+    <tag>HEAD</tag>
+  </scm>
+
+  <artifactId>zeromq-routingtable.integrationtest</artifactId>
+  <version>0.4.1-SNAPSHOT</version>
+
+  <dependencies>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>zeromq-routingtable.implementation</artifactId>
+        <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>clustering.services</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.1-SNAPSHOT</version>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal.implementation</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>containermanager</artifactId>
+          <version>0.5.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>containermanager.it.implementation</artifactId>
+          <version>0.5.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>clustering.stub</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+        <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+       <groupId>org.ops4j.pax.exam</groupId>
+       <artifactId>pax-exam-container-native</artifactId>
+       <scope>test</scope>
+     </dependency>
+     <dependency>
+       <groupId>org.ops4j.pax.exam</groupId>
+       <artifactId>pax-exam-junit4</artifactId>
+       <scope>test</scope>
+     </dependency>
+     <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-link-mvn</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.ops4j.pax.url</groupId>
+        <artifactId>pax-url-aether</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>log4j-over-slf4j</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-core</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-classic</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>eclipselink</groupId>
+        <artifactId>javax.resource</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>com.google.guava</groupId>
+          <artifactId>guava</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal</artifactId>
+          <version>0.5.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-binding</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-common</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-connector-api</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-util</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-api</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-util</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-container-native</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-link-mvn</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-manager</artifactId>
+          <version>0.2.3-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>equinoxSDK381</groupId>
+          <artifactId>org.eclipse.osgi</artifactId>
+          <version>3.8.1.v20120830-144521</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>log4j-over-slf4j</artifactId>
+          <version>1.7.2</version>
+      </dependency>
+      <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-core</artifactId>
+          <version>1.0.9</version>
+      </dependency>
+      <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>1.0.9</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+          <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+          <version>4.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+          <artifactId>xtend-lib-osgi</artifactId>
+          <version>2.4.3</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>clustering.services</artifactId>
+          <version>0.4.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>test</scope>
+      </dependency>
+
+      <dependency>
+          <groupId>equinoxSDK381</groupId>
+          <artifactId>org.eclipse.osgi</artifactId>
+          <version>3.8.1.v20120830-144521</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+  </dependencies>
+  <properties>
+    <!-- Sonar jacoco plugin to get integration test coverage info -->
+    <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+  </properties>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.jacoco</groupId>
+          <artifactId>jacoco-maven-plugin</artifactId>
+          <version>0.5.3.201107060350</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>${jacoco.version}</version>
+        <configuration>
+          <destFile>../implementation/target/jacoco-it.exec</destFile>
+          <includes>org.opendaylight.controller.*</includes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>pre-test</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>post-test</id>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java
new file mode 100644 (file)
index 0000000..3b6d398
--- /dev/null
@@ -0,0 +1,290 @@
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Set;
+
+
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+
+
+
+@RunWith(PaxExam.class)
+public class
+        ZeroMQRoutingTableTestIT {
+    private Logger log = LoggerFactory
+            .getLogger(ZeroMQRoutingTableTestIT.class);
+
+    public static final String ODL = "org.opendaylight.controller";
+    public static final String YANG = "org.opendaylight.yangtools";
+    public static final String CONTROLLER = "org.opendaylight.controller";
+    public static final String YANGTOOLS = "org.opendaylight.yangtools";
+    // get the OSGI bundle context
+    @Inject
+    private BundleContext bc;
+    @Inject
+    private RoutingTable routingTable = null;
+
+    // Configure the OSGi container
+    @Configuration
+    public Option[] config() {
+        return options(
+                //
+                systemProperty("logback.configurationFile").value(
+                        "file:" + PathUtils.getBaseDir()
+                                + "/src/test/resources/logback.xml"),
+                // To start OSGi console for inspection remotely
+                systemProperty("osgi.console").value("2401"),
+                // Set the systemPackages (used by clustering)
+                systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+                // List framework bundles
+
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.console").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.util").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.osgi.services").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.ds").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.command").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.runtime").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.shell").versionAsInProject(),
+                // List logger bundles
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
+                // List all the bundles on which the test case depends
+                mavenBundle(ODL,
+                        "clustering.services").versionAsInProject(),
+
+                mavenBundle(ODL, "sal").versionAsInProject(),
+                mavenBundle(ODL,
+                        "sal.implementation").versionAsInProject(),
+                mavenBundle(ODL, "containermanager").versionAsInProject(),
+                mavenBundle(ODL,
+                        "containermanager.it.implementation").versionAsInProject(),
+                mavenBundle("org.jboss.spec.javax.transaction",
+                        "jboss-transaction-api_1.1_spec").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager").versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager.shell").versionAsInProject(),
+                mavenBundle("eclipselink", "javax.resource").versionAsInProject(),
+
+                mavenBundle("com.google.guava","guava").versionAsInProject(),
+                // List logger bundles
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j")
+                        .versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core")
+                        .versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic")
+                        .versionAsInProject(),
+
+                mavenBundle(ODL, "clustering.services")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "clustering.stub")
+                        .versionAsInProject(),
+
+
+                // List all the bundles on which the test case depends
+                mavenBundle(ODL, "sal")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "sal-connector-api")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "zeromq-routingtable.implementation")
+                        .versionAsInProject(),
+
+                mavenBundle("org.jboss.spec.javax.transaction",
+                        "jboss-transaction-api_1.1_spec").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3")
+                        .versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager")
+                        .versionAsInProject(),
+
+                mavenBundle(ODL,
+                        "sal-core-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-data-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-model-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-binding")
+                        .versionAsInProject(),
+
+                mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
+                mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+
+
+                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+
+
+                mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
+                mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
+
+                mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+
+                mavenBundle(YANG, "concepts").versionAsInProject(),
+                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+                mavenBundle(YANG, "yang-common").versionAsInProject(), //
+                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
+                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(),
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+
+                mavenBundle(ODL, "sal-common").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
+                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(ODL, "config-api").versionAsInProject(), //
+                mavenBundle(ODL, "config-manager").versionAsInProject(), //
+                mavenBundle("commons-io", "commons-io").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+
+                mavenBundle(ODL, "sal-binding-api").versionAsInProject(), //
+                mavenBundle(ODL, "sal-binding-config").versionAsInProject(),
+                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
+                mavenBundle(YANG, "yang-data-impl").versionAsInProject(), //
+                mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
+                mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
+                mavenBundle(YANG, "yang-parser-api").versionAsInProject(),
+                mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+
+
+                mavenBundle(YANG, "binding-generator-spi").versionAsInProject(), //
+                mavenBundle(YANG, "binding-model-api").versionAsInProject(), //
+                mavenBundle(YANG, "binding-generator-util").versionAsInProject(),
+                mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+                mavenBundle(YANG, "binding-type-provider").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-api").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-spi").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-impl").versionAsInProject(),
+
+
+                mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
+                mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
+                mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
+
+                mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+
+                mavenBundle(YANG, "concepts").versionAsInProject(),
+                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+                mavenBundle(YANG, "yang-common").versionAsInProject(), //
+                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
+                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(),
+
+                junitBundles());
+    }
+
+    private String stateToString(int state) {
+        switch (state) {
+            case Bundle.ACTIVE:
+                return "ACTIVE";
+            case Bundle.INSTALLED:
+                return "INSTALLED";
+            case Bundle.RESOLVED:
+                return "RESOLVED";
+            case Bundle.UNINSTALLED:
+                return "UNINSTALLED";
+            default:
+                return "Not CONVERTED";
+        }
+    }
+
+    @Test
+  public  void testAddGlobalRoute () throws Exception{
+       RoutingIdentifierImpl rii  = new RoutingIdentifierImpl();
+       routingTable.addGlobalRoute(rii,"172.27.12.1:5000");
+
+       Set<String> routes = routingTable.getRoutes(rii);
+
+       for(String route:routes){
+           Assert.assertEquals(route,"172.27.12.1:5000");
+       }
+
+
+    }
+
+
+   class RoutingIdentifierImpl implements RpcRouter.RouteIdentifier,Serializable {
+
+       private final URI namespace = URI.create("http://cisco.com/example");
+       private final QName QNAME = new QName(namespace,"global");
+       private final QName instance = new QName(URI.create("127.0.0.1"),"local");
+
+       @Override
+       public QName getContext() {
+           return QNAME;
+       }
+
+       @Override
+       public QName getType() {
+           return QNAME;
+       }
+
+       @Override
+       public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+           return InstanceIdentifier.of(instance);
+       }
+   }
+
+
+
+
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..6d9dfda
--- /dev/null
@@ -0,0 +1,12 @@
+<configuration scan="true">
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+      </pattern>
+    </encoder>
+  </appender>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>