Inserted set and get controllers methods in ovsdb controller config

Change-Id: I791ff2ae159d0ac50beff22abda2b187913428f6
diff --git a/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java b/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java
new file mode 100644
index 0000000..328d470
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/DeviceControllersCommand.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+
+/**
+ * Sets role of the controller node for the given infrastructure device.
+ */
+@Command(scope = "onos", name = "device-controllers",
+        description = "gets the list of controllers for the given infrastructure device")
+public class DeviceControllersCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "uri", description = "Device ID",
+            required = true, multiValued = false)
+    String uri = null;
+    private DeviceId deviceId;
+
+    @Override
+    protected void execute() {
+        DriverService service = get(DriverService.class);
+        deviceId = DeviceId.deviceId(uri);
+        DriverHandler h = service.createHandler(deviceId);
+        ControllerConfig config = h.behaviour(ControllerConfig.class);
+        config.getControllers().forEach(c -> print(c.target()));
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java b/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
new file mode 100644
index 0000000..c369379
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Sets role of the controller node for the given infrastructure device.
+ */
+@Command(scope = "onos", name = "device-setcontrollers",
+        description = "sets the list of controllers for the given infrastructure device")
+public class DeviceSetControllersCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "uri", description = "Device ID",
+            required = true, multiValued = false)
+    String uri = null;
+
+    @Argument(index = 1, name = "controllersListStrings", description = "list of " +
+            "controllers to set for the specified device",
+            required = true, multiValued = true)
+    String[] controllersListStrings = null;
+
+    private DeviceId deviceId;
+    private List<ControllerInfo> newControllers = new ArrayList<>();
+
+    @Override
+    protected void execute() {
+
+        Arrays.asList(controllersListStrings).forEach(
+                cInfoString -> newControllers.add(new ControllerInfo(cInfoString)));
+        DriverService service = get(DriverService.class);
+        deviceId = DeviceId.deviceId(uri);
+        DriverHandler h = service.createHandler(deviceId);
+        ControllerConfig config = h.behaviour(ControllerConfig.class);
+        print("before:");
+        config.getControllers().forEach(c -> print(c.target()));
+
+        config.setControllers(newControllers);
+        print("after:");
+        config.getControllers().forEach(c -> print(c.target()));
+        print("size %d", config.getControllers().size());
+    }
+
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index c28824a..e7fe5c4 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -105,6 +105,18 @@
             </completers>
         </command>
         <command>
+            <action class="org.onosproject.cli.net.DeviceControllersCommand"/>
+            <completers>
+                <ref component-id="deviceIdCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.DeviceSetControllersCommand"/>
+            <completers>
+                <ref component-id="deviceIdCompleter"/>
+            </completers>
+        </command>
+        <command>
             <action class="org.onosproject.cli.net.DeviceRemoveCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
index bb8a788..cd7cb97 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java
@@ -15,23 +15,27 @@
  */
 package org.onosproject.net.behaviour;
 
+import org.onosproject.net.driver.HandlerBehaviour;
+
 import java.util.List;
 
 /**
  * Device behaviour to obtain and set controllers at the device.
  */
-public interface ControllerConfig {
+public interface ControllerConfig extends HandlerBehaviour {
 
     //TODO: add other controller parameters as needed.
 
     /**
      * Obtain the list of controller which are currently configured.
+     *
      * @return a list for controller descriptions
      */
     List<ControllerInfo> getControllers();
 
     /**
      * Set a list of controllers on a device.
+     *
      * @param controllers a list of controller descriptions
      */
     void setControllers(List<ControllerInfo> controllers);
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
index 9ff808a..ded3b3a 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
@@ -15,24 +15,112 @@
  */
 package org.onosproject.net.behaviour;
 
+import com.google.common.base.Preconditions;
 import org.onlab.packet.IpAddress;
 
+import java.util.Objects;
+
 /**
  * Represents information for a device to connect to a controller.
  */
 public class ControllerInfo {
 
-    public final IpAddress ip;
-    public final int tcpPort;
+    private IpAddress ip = IpAddress.valueOf("0.0.0.0");
+    private int port = 6653;
+    private String type = "error";
 
     /**
      * Information for contacting the controller.
      *
-     * @param ip the ip address
-     * @param tcpPort the tcp port
+     * @param ip   the ip address
+     * @param port the tcp port
      */
-    public ControllerInfo(IpAddress ip, int tcpPort) {
+    public ControllerInfo(IpAddress ip, int port, String type) {
         this.ip = ip;
-        this.tcpPort = tcpPort;
+        this.port = port;
+        this.type = type;
+    }
+
+    /**
+     * Information for contacting the controller, if some information
+     * is not contained in the target string because it's optional
+     * it's leaved as in the field declaration (default values).
+     *
+     * @param target column returned from ovsdb query
+     */
+    public ControllerInfo(String target) {
+        String[] data = target.split(":");
+        this.type = data[0];
+        Preconditions.checkArgument(!data[0].contains("unix"),
+                                    "Unable to create controller info " +
+                                            "from {} because it's based " +
+                                            "on unix sockets", target);
+        if (data[0].startsWith("p")) {
+            if (data.length >= 2) {
+                this.port = Integer.parseInt(data[1]);
+            }
+            if (data.length == 3) {
+                this.ip = IpAddress.valueOf(data[2]);
+            }
+        } else {
+            this.ip = IpAddress.valueOf(data[1]);
+            if (data.length == 3) {
+                this.port = Integer.parseInt(data[2]);
+            }
+        }
+    }
+
+    /**
+     * Exposes the ip address of the controller.
+     *
+     * @return IpAddress ip address
+     */
+    public IpAddress ip() {
+        return ip;
+    }
+
+    /**
+     * Exposes the tcp port of the controller.
+     *
+     * @return int tcp port
+     */
+    public int port() {
+        return port;
+    }
+
+    /**
+     * Exposes the type of the controller connection.
+     *
+     * @return String type
+     */
+    public String type() {
+        return type;
+    }
+
+    public String target() {
+        if (type.startsWith("p")) {
+            return type + ":" + port + ":" + ip;
+        } else {
+            return type + ":" + ip + ":" + port;
+        }
+    }
+
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(ip, port, type);
+    }
+
+    @Override
+    public boolean equals(Object toBeCompared) {
+        if (toBeCompared instanceof ControllerInfo) {
+            ControllerInfo controllerInfo = (ControllerInfo) toBeCompared;
+            if (controllerInfo.type().equals(this.type)
+                    && controllerInfo.ip().equals(this.ip())
+                    && controllerInfo.port() == this.port) {
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java
new file mode 100644
index 0000000..ece7f19
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.behaviour;
+
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onlab.packet.IpAddress;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test for ControllerInfo class.
+ */
+public class ControllerInfoTest {
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void tcpSslFormat() {
+        String target = "tcp:192.168.1.1:6653";
+        ControllerInfo controllerInfo = new ControllerInfo(target);
+        assertEquals("wrong type", controllerInfo.type(), "tcp");
+        assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+        assertEquals("wrong port", controllerInfo.port(), 6653);
+
+    }
+
+    @Test
+    public void ptcpPsslFormat() {
+        String target = "ptcp:6653:192.168.1.1";
+        ControllerInfo controllerInfo = new ControllerInfo(target);
+        assertEquals("wrong type", controllerInfo.type(), "ptcp");
+        assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+        assertEquals("wrong port", controllerInfo.port(), 6653);
+
+    }
+
+    @Test
+    public void unixFormat() {
+        String target = "unix:file";
+        thrown.expect(IllegalArgumentException.class);
+        ControllerInfo controllerInfo = new ControllerInfo(target);
+        assertTrue("wrong type", controllerInfo.type().contains("unix"));
+        assertNull("wrong ip", controllerInfo.ip());
+        assertEquals("wrong port", controllerInfo.port(), -1);
+
+    }
+
+    @Test
+    public void defaultValues() {
+        String target = "tcp:192.168.1.1";
+        ControllerInfo controllerInfo = new ControllerInfo(target);
+        assertEquals("wrong type", controllerInfo.type(), "tcp");
+        assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1"));
+        assertEquals("wrong port", controllerInfo.port(), 6653);
+        String target1 = "ptcp:5000:";
+        ControllerInfo controllerInfo2 = new ControllerInfo(target1);
+        assertEquals("wrong type", controllerInfo2.type(), "ptcp");
+        assertEquals("wrong ip", controllerInfo2.ip(), IpAddress.valueOf("0.0.0.0"));
+        assertEquals("wrong port", controllerInfo2.port(), 5000);
+        String target2 = "ptcp:";
+        ControllerInfo controllerInfo3 = new ControllerInfo(target2);
+        assertEquals("wrong type", controllerInfo3.type(), "ptcp");
+        assertEquals("wrong ip", controllerInfo3.ip(), IpAddress.valueOf("0.0.0.0"));
+        assertEquals("wrong port", controllerInfo3.port(), 6653);
+    }
+
+
+    @Test
+    public void testEquals() {
+        String target1 = "ptcp:6653:192.168.1.1";
+        ControllerInfo controllerInfo1 = new ControllerInfo(target1);
+        String target2 = "ptcp:6653:192.168.1.1";
+        ControllerInfo controllerInfo2 = new ControllerInfo(target2);
+        assertTrue("wrong equals method", controllerInfo1.equals(controllerInfo2));
+    }
+
+    @Test
+    public void testListEquals() {
+        String target1 = "ptcp:6653:192.168.1.1";
+        ControllerInfo controllerInfo1 = new ControllerInfo(target1);
+        String target2 = "ptcp:6653:192.168.1.1";
+        ControllerInfo controllerInfo2 = new ControllerInfo(target2);
+        String target3 = "tcp:192.168.1.1:6653";
+        ControllerInfo controllerInfo3 = new ControllerInfo(target3);
+        String target4 = "tcp:192.168.1.1:6653";
+        ControllerInfo controllerInfo4 = new ControllerInfo(target4);
+        List<ControllerInfo> list1 = new ArrayList<>(Arrays.asList(controllerInfo1, controllerInfo3));
+        List<ControllerInfo> list2 = new ArrayList<>(Arrays.asList(controllerInfo2, controllerInfo4));
+        assertTrue("wrong equals list method", list1.equals(list2));
+    }
+}
diff --git a/drivers/pom.xml b/drivers/pom.xml
index 749a68c..56a39a8 100644
--- a/drivers/pom.xml
+++ b/drivers/pom.xml
@@ -55,8 +55,8 @@
          <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-core-serializers</artifactId>
-            <version>1.4.0-SNAPSHOT</version>
-        </dependency>
+             <version>${project.version}</version>
+         </dependency>
         <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-ovsdb-api</artifactId>
@@ -72,6 +72,25 @@
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.scr.annotations</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-ovsdb-api</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java b/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java
new file mode 100644
index 0000000..a00d3db
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbControllerConfig.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.driver.ovsdb;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.ovsdb.controller.OvsdbBridge;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.util.Tools.delay;
+
+/**
+ * Implementation of controller config which allows to get and set controllers.
+ */
+public class OvsdbControllerConfig extends AbstractHandlerBehaviour implements ControllerConfig {
+    @Override
+    public List<ControllerInfo> getControllers() {
+        DriverHandler handler = handler();
+        OvsdbClientService clientService = getOvsdbClientService(handler);
+        Set<ControllerInfo> controllers = clientService.getControllers(
+                handler().data().deviceId());
+        return new ArrayList<>(controllers);
+    }
+
+    @Override
+    public void setControllers(List<ControllerInfo> controllers) {
+        DriverHandler handler = handler();
+        OvsdbClientService clientService = getOvsdbClientService(handler);
+        if (!clientService.getControllers(handler().data().deviceId())
+                .equals(controllers)) {
+            clientService.setControllersWithDeviceId(handler().
+                    data().deviceId(), controllers);
+        }
+    }
+
+    // Used for getting OvsdbClientService.
+    private OvsdbClientService getOvsdbClientService(DriverHandler handler) {
+        OvsdbController ovsController = handler.get(OvsdbController.class);
+        DeviceService deviceService = handler.get(DeviceService.class);
+        DeviceId ofDeviceId = handler.data().deviceId();
+        String[] mgmtAddress = deviceService.getDevice(ofDeviceId)
+                .annotations().value(AnnotationKeys.MANAGEMENT_ADDRESS).split(":");
+        String targetIp = mgmtAddress[0];
+        TpPort targetPort = null;
+        if (mgmtAddress.length > 1) {
+            targetPort = TpPort.tpPort(Integer.parseInt(mgmtAddress[1]));
+        }
+
+        List<OvsdbNodeId> nodeIds = ovsController.getNodeIds().stream()
+                .filter(nodeId -> nodeId.getIpAddress().equals(targetIp))
+                .collect(Collectors.toList());
+        if (nodeIds.size() == 0) {
+            //TODO decide what port?
+            ovsController.connect(IpAddress.valueOf(targetIp),
+                                  targetPort == null ? TpPort.tpPort(6640) : targetPort);
+            delay(1000); //FIXME... connect is async
+        }
+        List<OvsdbClientService> clientServices = ovsController.getNodeIds().stream()
+                .filter(nodeId -> nodeId.getIpAddress().equals(targetIp))
+                .map(ovsController::getOvsdbClient)
+                .filter(cs -> cs.getBridges().stream().anyMatch(b -> dpidMatches(b, ofDeviceId)))
+                .collect(Collectors.toList());
+        checkState(clientServices.size() > 0, "No clientServices found");
+        //FIXME add connection to management address if null --> done ?
+        return clientServices.size() > 0 ? clientServices.get(0) : null;
+    }
+
+    private static boolean dpidMatches(OvsdbBridge bridge, DeviceId deviceId) {
+        String bridgeDpid = "of:" + bridge.datapathId().value();
+        String ofDpid = deviceId.toString();
+        return bridgeDpid.equals(ofDpid);
+    }
+}
\ No newline at end of file
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index aea743f..5059d4b 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -30,6 +30,8 @@
             manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
+        <behaviour api="org.onosproject.net.behaviour.ControllerConfig"
+                   impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/>
     </driver>
     <driver name="ovs-corsa" extends="ovs"
             manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
diff --git a/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java b/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
new file mode 100644
index 0000000..4a91efc
--- /dev/null
+++ b/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.driver.ovsdb;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerConfig;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.driver.DefaultDriver;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.ovsdb.controller.driver.OvsdbClientServiceAdapter;
+import org.onosproject.ovsdb.controller.driver.OvsdbControllerAdapter;
+
+/**
+ * Created by Andrea on 10/7/15.
+ */
+public class OvsdbControllerConfigTest {
+
+
+    private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo");
+
+    private DefaultDriver ddc;
+    private DefaultDriverData data;
+    private DefaultDriverHandler handler;
+
+    private TestDeviceService deviceService = new TestDeviceService();
+    private TestOvsdbController controller = new TestOvsdbController();
+    private TestOvsdbClient client = new TestOvsdbClient();
+
+    private OvsdbControllerConfig controllerConfig;
+
+
+    @Before
+    public void setUp() {
+        controllerConfig = new OvsdbControllerConfig();
+
+        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+                                ImmutableMap.of(ControllerConfig.class,
+                                                OvsdbControllerConfig.class),
+                                ImmutableMap.of("foo", "bar"));
+        data = new DefaultDriverData(ddc, DEVICE_ID);
+        handler = new DefaultDriverHandler(data);
+        //handler.controllerConfig.setHandler(handler);
+        //TODO setTestService directory on handler
+        //TODO setup ovsdb fake controller with fake ovsdbclient
+        //TODO setup fake device service
+    }
+
+    @Test
+    public void testGetControllers() throws Exception {
+//        DriverService driverService = new Driv
+//        AbstractBehaviour ab = new AbstractBehaviour();
+//        DriverHandler handler = handler();
+//        List<ControllerInfo> controllersList =
+//              controllerConfig.getControllers(DeviceId.deviceId("0000000000000018"));
+//        log.info("controllers " + controllersList);
+
+    }
+
+    @Test
+    public void testSetControllers() throws Exception {
+
+    }
+
+
+    private class TestDeviceService extends DeviceServiceAdapter {
+
+    }
+
+    private class TestOvsdbController extends OvsdbControllerAdapter {
+
+
+    }
+
+    private class TestOvsdbClient extends OvsdbClientServiceAdapter {
+
+    }
+}
\ No newline at end of file
diff --git a/ovsdb/api/pom.xml b/ovsdb/api/pom.xml
index 7089216..c264ae9 100644
--- a/ovsdb/api/pom.xml
+++ b/ovsdb/api/pom.xml
@@ -48,6 +48,10 @@
         </dependency>
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onos-ovsdb-rfc</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
index c5f2092..833f5fe 100644
--- a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java
@@ -15,19 +15,20 @@
  */
 package org.onosproject.ovsdb.controller;
 
-import java.util.List;
-import java.util.Set;
-
+import com.google.common.util.concurrent.ListenableFuture;
 import org.onlab.packet.IpAddress;
-
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.ovsdb.rfc.jsonrpc.OvsdbRPC;
 import org.onosproject.ovsdb.rfc.message.OperationResult;
 import org.onosproject.ovsdb.rfc.message.TableUpdates;
 import org.onosproject.ovsdb.rfc.notation.Row;
+import org.onosproject.ovsdb.rfc.notation.UUID;
 import org.onosproject.ovsdb.rfc.operations.Operation;
 import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
 
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Set;
 
 /**
  * Represents to provider facing side of a node.
@@ -85,10 +86,33 @@
     Set<OvsdbBridge> getBridges();
 
     /**
+     * Gets controllers of the node.
+     *
+     * @return set of controllers; empty if no controller is find
+     */
+    Set<ControllerInfo> getControllers(DeviceId openflowDeviceId);
+
+    /**
+     * sets the controllers of the node to the ones passed in the list.
+     *
+     * @param bridgeUuid  UUid for the bridge we are settings the controls on
+     * @param controllers of controllers; empty if no controller is find
+     */
+    void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers);
+
+    /**
+     * sets the controllers of the node to the ones passed in the list.
+     *
+     * @param deviceId  deviceId for the bridge we are settings the controls on
+     * @param controllers of controllers; empty if no controller is find
+     */
+    void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers);
+
+    /**
      * Creates a port.
      *
      * @param bridgeName bridge name
-     * @param portName port name
+     * @param portName   port name
      */
     void createPort(String bridgeName, String portName);
 
@@ -96,7 +120,7 @@
      * Drops a port.
      *
      * @param bridgeName bridge name
-     * @param portName port name
+     * @param portName   port name
      */
     void dropPort(String bridgeName, String portName);
 
@@ -125,7 +149,7 @@
     /**
      * Gets the Port uuid.
      *
-     * @param portName port name
+     * @param portName   port name
      * @param bridgeUuid bridge uuid
      * @return port uuid, empty if no uuid is find
      */
@@ -143,7 +167,7 @@
     /**
      * Gets the Controller uuid.
      *
-     * @param controllerName controller name
+     * @param controllerName   controller name
      * @param controllerTarget controller target
      * @return controller uuid, empty if no uuid is find
      */
@@ -169,7 +193,7 @@
      * Gets the ovsdb table updates.
      *
      * @param dbName database name
-     * @param id random uuid
+     * @param id     random uuid
      * @return table updates
      */
     ListenableFuture<TableUpdates> monitorTables(String dbName, String id);
@@ -177,7 +201,7 @@
     /**
      * Gets the ovsdb config operation result.
      *
-     * @param dbName database name
+     * @param dbName     database name
      * @param operations the list of operations
      * @return operation results
      */
@@ -187,7 +211,7 @@
     /**
      * Gets the ovsdb database schema from local.
      *
-     * @param  dbName database name
+     * @param dbName database name
      * @return database schema
      */
     DatabaseSchema getDatabaseSchema(String dbName);
@@ -195,9 +219,9 @@
     /**
      * Gets the ovsdb row from the local ovsdb store.
      *
-     * @param dbName database name
+     * @param dbName    database name
      * @param tableName table name
-     * @param uuid row uuid
+     * @param uuid      row uuid
      * @return row ovsdb row
      */
     Row getRow(String dbName, String tableName, String uuid);
@@ -205,19 +229,19 @@
     /**
      * Removes the ovsdb row from the local ovsdb store.
      *
-     * @param dbName database name
+     * @param dbName    database name
      * @param tableName table name
-     * @param uuid row uuid
+     * @param uuid      row uuid
      */
     void removeRow(String dbName, String tableName, String uuid);
 
     /**
      * Updates the local ovsdb store.
      *
-     * @param dbName database name
+     * @param dbName    database name
      * @param tableName table name
-     * @param uuid row uuid
-     * @param row ovsdb row
+     * @param uuid      row uuid
+     * @param row       ovsdb row
      */
     void updateOvsdbStore(String dbName, String tableName, String uuid, Row row);
 
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
index 1b41be9..5dc4cb1 100644
--- a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java
@@ -15,19 +15,18 @@
  */
 package org.onosproject.ovsdb.controller.driver;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import io.netty.channel.Channel;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
 import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
 import org.onosproject.ovsdb.controller.OvsdbBridge;
 import org.onosproject.ovsdb.controller.OvsdbBridgeName;
 import org.onosproject.ovsdb.controller.OvsdbClientService;
@@ -71,14 +70,17 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 
 /**
  * An representation of an ovsdb client.
@@ -168,9 +170,8 @@
     /**
      * Gets the ovsdb row store.
      *
-     * @param dbName the ovsdb database name
+     * @param dbName    the ovsdb database name
      * @param tableName the ovsdb table name
-     *
      * @return ovsRowStore, empty if row store is find
      */
     private OvsdbRowStore getRowStore(String dbName, String tableName) {
@@ -184,9 +185,9 @@
     /**
      * Gets the ovsdb row.
      *
-     * @param dbName the ovsdb database name
+     * @param dbName    the ovsdb database name
      * @param tableName the ovsdb table name
-     * @param uuid the key of the row
+     * @param uuid      the key of the row
      * @return row, empty if row is find
      */
     @Override
@@ -394,7 +395,7 @@
         port.setName(portName);
         if (portUuid == null) {
             insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
-                      "ports", bridgeUuid, port.getRow());
+                         "ports", bridgeUuid, port.getRow());
         } else {
             updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
         }
@@ -414,7 +415,7 @@
         if (portUuid != null) {
             log.info("Port {} delete", portName);
             deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
-                      OvsdbConstant.BRIDGE, "ports");
+                         OvsdbConstant.BRIDGE, "ports");
         }
     }
 
@@ -455,8 +456,8 @@
 
             bridge.setName(bridgeName);
             bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
-                                   OvsdbConstant.DATABASENAME, "bridges",
-                                   ovsUuid, bridge.getRow());
+                                      OvsdbConstant.DATABASENAME, "bridges",
+                                      ovsUuid, bridge.getRow());
 
             if (bridgeUuid != null) {
                 Port port = (Port) TableGenerator.createTable(dbSchema,
@@ -466,7 +467,7 @@
                     port.setName(bridgeName);
 
                     insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
-                              port.getRow());
+                                 port.getRow());
                 }
             }
 
@@ -475,7 +476,7 @@
             updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
         }
 
-        setController(bridgeUuid);
+        setControllerAuto(bridgeUuid);
         log.info("Create bridge success");
     }
 
@@ -484,10 +485,10 @@
      *
      * @param bridgeUuid bridge uuid
      */
-    private void setController(String bridgeUuid) {
+    private void setControllerAuto(String bridgeUuid) {
         String controllerUuid = null;
         String iPAddress = IpAddress.valueOf(((InetSocketAddress) channel
-                                                     .localAddress())
+                .localAddress())
                                                      .getAddress()
                                                      .getHostAddress())
                 .toString();
@@ -495,18 +496,118 @@
         String target = "tcp:" + iPAddress + ":" + OvsdbConstant.OFPORT;
         log.debug("controller IP {}: port {}", iPAddress, OvsdbConstant.OFPORT);
 
+        setController(bridgeUuid, target);
+
+    }
+
+    /**
+     * Sets the Controllers.
+     *
+     * @param bridgeUuid bridge uuid
+     */
+    @Override
+    public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
+
         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+        if (dbSchema == null) {
+            log.debug("There is no schema");
+            return;
+        }
+        List<Controller> oldControllers = getControllers(bridgeUuid);
+        if (oldControllers == null) {
+            log.warn("There are no controllers");
+            return;
+        }
+
+        Set<UUID> newControllerUuids = new HashSet<>();
+
+        Set<ControllerInfo> newControllers = new HashSet<>(controllers);
+        List<Controller> removeControllers = new ArrayList<>();
+        oldControllers.forEach(controller -> {
+            ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
+            if (newControllers.contains(controllerInfo)) {
+                newControllers.remove(controllerInfo);
+                newControllerUuids.add(controller.getRow().uuid());
+            } else {
+                removeControllers.add(controller);
+            }
+        });
+        OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
+                                                       OvsdbConstant.CONTROLLER);
+        if (controllerRowStore == null) {
+            log.debug("There is no controller table");
+            return;
+        }
+
+//        removeControllers.forEach(c -> controllerRowStore.deleteRow(c.getRow().uuid().value()));
+        removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
+                                                    OvsdbConstant.BRIDGE, "controller"));
+
+        newControllers.stream().map(c -> {
+            Controller controller = (Controller) TableGenerator
+                    .createTable(dbSchema, OvsdbTable.CONTROLLER);
+            controller.setTarget(c.target());
+            return controller;
+        }).forEach(c -> {
+//            UUID uuid = c.getRow().uuid();
+//            controllerRowStore.insertRow(uuid.value(), c.getRow());
+//            newControllerUuids.add(uuid);
+
+            String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
+                                       OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
+                                       c.getRow());
+            log.warn("insertConfig uuid {}", uuid);
+            log.warn("row uuid {}", c.getRow().uuid());
+            //log.warn("rowStore uuid {}", controllerRowStore.getRowStore());
+            newControllerUuids.add(UUID.uuid(uuid));
+
+        });
+
+        OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+                                             OvsdbConstant.BRIDGE);
+        if (rowStore == null) {
+            log.debug("There is no bridge table");
+            return;
+        }
+
+        Row bridgeRow = rowStore.getRow(bridgeUuid.value());
+        Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
+        bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
+        updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
+
+        //rowStore.insertRow(bridgeUuid.value(), bridge.getRow()); //TODO do we need to do this?
+    }
+
+    /**
+     * Sets the Controllers.
+     *
+     * @param deviceId bridge uuid
+     */
+    @Override
+    public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
+        setControllersWithUUID(getBridgeUUID(deviceId), controllers);
+    }
+
+    private void setController(String bridgeUuid, String target) {
+        String controllerUuid;
+        DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+
+        // 1. get the bridge row
+        // 2. delete different controllers and save the same controller.
+        // 3. add new controllers
+        // 4. update bridge row
+
+
+        controllerUuid = getControllerUuid(OvsdbConstant.CONTROLLER, target);
+
         Controller controller = (Controller) TableGenerator
                 .createTable(dbSchema, OvsdbTable.CONTROLLER);
-
         if (controller != null) {
-            controller.setTarget(target);
-            controllerUuid = getControllerUuid(OvsdbConstant.CONTROLLER, target);
             if (controllerUuid == null) {
 
                 insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
-                          OvsdbConstant.BRIDGE, "controller", bridgeUuid,
-                          controller.getRow());
+                             OvsdbConstant.BRIDGE, "controller", bridgeUuid,
+                             controller.getRow());
 
             } else {
 
@@ -514,12 +615,11 @@
                         .createTable(dbSchema, OvsdbTable.BRIDGE);
                 Set<UUID> controllerUuids = new HashSet<>();
                 controllerUuids.add(UUID.uuid(controllerUuid));
-                bridge.setController(controllerUuids);
+                bridge.setController(OvsdbSet.ovsdbSet(controllerUuids));
                 updateConfig(OvsdbConstant.CONTROLLER, "_uuid", bridgeUuid, bridge.getRow());
 
             }
         }
-
     }
 
     @Override
@@ -530,7 +630,7 @@
             return;
         }
         deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
-                  OvsdbConstant.DATABASENAME, "bridges");
+                     OvsdbConstant.DATABASENAME, "bridges");
     }
 
     @Override
@@ -554,7 +654,7 @@
 
         if (portUuid == null) {
             portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
-                      "ports", bridgeUuid, port.getRow());
+                                    "ports", bridgeUuid, port.getRow());
         } else {
             updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
         }
@@ -595,7 +695,7 @@
                 options.put("remote_ip", dstIp.toString());
                 tunInterface.setOptions(options);
                 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
-                          tunInterface.getRow());
+                             tunInterface.getRow());
                 log.info("Tunnel added success", tunInterface);
 
             }
@@ -619,7 +719,7 @@
         if (portUUID != null) {
             log.info("Delete tunnel");
             deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
-                      OvsdbConstant.BRIDGE, "ports");
+                         OvsdbConstant.BRIDGE, "ports");
         }
 
         return;
@@ -628,16 +728,15 @@
     /**
      * Delete transact config.
      *
-     * @param childTableName child table name
-     * @param childColumnName child column name
-     * @param childUuid child row uuid
-     * @param parentTableName parent table name
+     * @param childTableName   child table name
+     * @param childColumnName  child column name
+     * @param childUuid        child row uuid
+     * @param parentTableName  parent table name
      * @param parentColumnName parent column
-     *
      */
     private void deleteConfig(String childTableName, String childColumnName,
-                           String childUuid, String parentTableName,
-                           String parentColumnName) {
+                              String childUuid, String parentTableName,
+                              String parentColumnName) {
         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
         TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
 
@@ -672,14 +771,13 @@
     /**
      * Update transact config.
      *
-     * @param tableName table name
+     * @param tableName  table name
      * @param columnName column name
-     * @param uuid uuid
-     * @param row the config data
-     *
+     * @param uuid       uuid
+     * @param row        the config data
      */
     private void updateConfig(String tableName, String columnName, String uuid,
-                           Row row) {
+                              Row row) {
         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
         TableSchema tableSchema = dbSchema.getTableSchema(tableName);
 
@@ -698,18 +796,17 @@
     /**
      * Insert transact config.
      *
-     * @param childTableName child table name
-     * @param childColumnName child column name
-     * @param parentTableName parent table name
+     * @param childTableName   child table name
+     * @param childColumnName  child column name
+     * @param parentTableName  parent table name
      * @param parentColumnName parent column
-     * @param parentUuid parent uuid
-     * @param row the config data
-     *
+     * @param parentUuid       parent uuid
+     * @param row              the config data
      * @return uuid, empty if no uuid is find
      */
     private String insertConfig(String childTableName, String childColumnName,
-                             String parentTableName, String parentColumnName,
-                             String parentUuid, Row row) {
+                                String parentTableName, String parentColumnName,
+                                String parentUuid, Row row) {
         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
         TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
 
@@ -741,7 +838,7 @@
         if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
             log.info("Handle port insert");
             Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
-                                                    row);
+                                                      row);
 
             if (intfInsert != null) {
                 operations.add(intfInsert);
@@ -772,8 +869,7 @@
      * Handles port insert.
      *
      * @param tableName ovsdb table interface
-     * @param portRow row of port
-     *
+     * @param portRow   row of port
      * @return insert, empty if null
      */
     private Insert handlePortInsertTable(String tableName, Row portRow) {
@@ -801,8 +897,7 @@
      * Gets tunnel name.
      *
      * @param tunnelType
-     * @param dstIp the remote ip address
-     *
+     * @param dstIp      the remote ip address
      * @return tunnel name
      */
     private String getTunnelName(String tunnelType, IpAddress dstIp) {
@@ -877,21 +972,17 @@
         }
         DatabaseSchema dbSchema = schema.get(dbName);
         if (dbSchema != null) {
-            Function<List<JsonNode>, List<OperationResult>> rowFunction =
-                    new Function<List<JsonNode>, List<OperationResult>>() {
-                @Override
-                public List<OperationResult> apply(List<JsonNode> input) {
-                    log.info("Get ovsdb operation result");
-                    List<OperationResult> result = FromJsonUtil
-                            .jsonNodeToOperationResult(input, operations);
+            Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
+                log.info("Get ovsdb operation result");
+                List<OperationResult> result = FromJsonUtil
+                        .jsonNodeToOperationResult(input, operations);
 
-                    if (result == null) {
-                        log.debug("The operation result is null");
-                        return null;
-                    }
-                    return result;
+                if (result == null) {
+                    log.debug("The operation result is null");
+                    return null;
                 }
-            };
+                return result;
+            });
             return Futures.transform(transact(dbSchema, operations),
                                      rowFunction);
         }
@@ -972,7 +1063,7 @@
 
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @SuppressWarnings({"rawtypes", "unchecked"})
     @Override
     public void processResult(JsonNode response) {
         log.debug("Handle result");
@@ -1042,6 +1133,105 @@
     }
 
     @Override
+    public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
+        UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
+        if (bridgeUuid == null) {
+            log.warn("bad bridge Uuid");
+            return null;
+        }
+        List<Controller> controllers = getControllers(bridgeUuid);
+        if (controllers == null) {
+            log.warn("bad list of controllers");
+            return null;
+        }
+        return controllers.stream().
+                map(controller -> new ControllerInfo(
+                        (String) controller.getTargetColumn()
+                                .data())).collect(Collectors.toSet());
+    }
+
+    private List<Controller> getControllers(UUID bridgeUuid) {
+        DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+        if (dbSchema == null) {
+            return null;
+        }
+        OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+                                             OvsdbConstant.BRIDGE);
+        if (rowStore == null) {
+            log.debug("There is no bridge table");
+            return null;
+        }
+
+        Row bridgeRow = rowStore.getRow(bridgeUuid.value());
+        Bridge bridge = (Bridge) TableGenerator.
+                getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
+
+        //FIXME remove log
+        log.warn("type of controller column", bridge.getControllerColumn()
+                .data().getClass());
+        Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
+                .getControllerColumn().data()).set();
+//        Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
+
+        OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
+                                                       OvsdbConstant.CONTROLLER);
+        if (controllerRowStore == null) {
+            log.debug("There is no controller table");
+            return null;
+        }
+
+        List<Controller> ovsdbControllers = new ArrayList<>();
+        ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
+        controllerTableRows.forEach((key, row) -> {
+            if (!controllerUuids.contains(UUID.uuid(key))) {
+                return;
+            }
+            Controller controller = (Controller) TableGenerator
+                    .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
+            ovsdbControllers.add(controller);
+        });
+        return ovsdbControllers;
+    }
+
+
+    private UUID getBridgeUUID(DeviceId openflowDeviceId) {
+        DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
+        if (dbSchema == null) {
+            return null;
+        }
+        OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
+                                             OvsdbConstant.BRIDGE);
+        if (rowStore == null) {
+            log.debug("There is no bridge table");
+            return null;
+        }
+
+        ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
+        final AtomicReference<UUID> uuid = new AtomicReference<>();
+        for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
+            Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
+                                                        entry.getValue(),
+                                                        OvsdbTable.BRIDGE);
+            if (matchesDpid(b, openflowDeviceId)) {
+                uuid.set(UUID.uuid(entry.getKey()));
+                break;
+            }
+        }
+        if (uuid.get() == null) {
+            log.debug("There is no bridge for {}", openflowDeviceId);
+        }
+        return uuid.get();
+
+    }
+
+    private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
+        String ofDpid = deviceId.toString().replace("of:", "");
+        Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
+        //TODO Set<String>
+        return ofDeviceIds.contains(ofDpid);
+    }
+
+    @Override
     public Set<OvsdbPort> getPorts() {
         Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
         OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
diff --git a/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java b/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java
new file mode 100644
index 0000000..71fee4f
--- /dev/null
+++ b/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbClientServiceAdapter.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.ovsdb.controller.driver;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ControllerInfo;
+import org.onosproject.ovsdb.controller.OvsdbBridge;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.onosproject.ovsdb.controller.OvsdbPort;
+import org.onosproject.ovsdb.controller.OvsdbTunnel;
+import org.onosproject.ovsdb.rfc.message.OperationResult;
+import org.onosproject.ovsdb.rfc.message.TableUpdates;
+import org.onosproject.ovsdb.rfc.notation.Row;
+import org.onosproject.ovsdb.rfc.notation.UUID;
+import org.onosproject.ovsdb.rfc.operations.Operation;
+import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test Adapter for OvsdbClientService.
+ */
+public class OvsdbClientServiceAdapter implements OvsdbClientService {
+
+    @Override
+    public OvsdbNodeId nodeId() {
+        return null;
+    }
+
+    @Override
+    public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
+
+    }
+
+    @Override
+    public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
+
+    }
+
+    @Override
+    public Set<OvsdbTunnel> getTunnels() {
+        return null;
+    }
+
+    @Override
+    public void createBridge(String bridgeName) {
+
+    }
+
+    @Override
+    public void dropBridge(String bridgeName) {
+
+    }
+
+    @Override
+    public Set<OvsdbBridge> getBridges() {
+        return null;
+    }
+
+    @Override
+    public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
+        return null;
+    }
+
+    @Override
+    public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
+
+    }
+
+    @Override
+    public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
+
+    }
+
+    @Override
+    public void createPort(String bridgeName, String portName) {
+
+    }
+
+    @Override
+    public void dropPort(String bridgeName, String portName) {
+
+    }
+
+    @Override
+    public Set<OvsdbPort> getPorts() {
+        return null;
+    }
+
+    @Override
+    public boolean isConnected() {
+        return false;
+    }
+
+    @Override
+    public String getBridgeUuid(String bridgeName) {
+        return null;
+    }
+
+    @Override
+    public String getPortUuid(String portName, String bridgeUuid) {
+        return null;
+    }
+
+    @Override
+    public String getInterfaceUuid(String portUuid, String portName) {
+        return null;
+    }
+
+    @Override
+    public String getControllerUuid(String controllerName, String controllerTarget) {
+        return null;
+    }
+
+    @Override
+    public String getOvsUuid(String dbName) {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<List<OperationResult>> transactConfig(String dbName, List<Operation> operations) {
+        return null;
+    }
+
+    @Override
+    public DatabaseSchema getDatabaseSchema(String dbName) {
+        return null;
+    }
+
+    @Override
+    public Row getRow(String dbName, String tableName, String uuid) {
+        return null;
+    }
+
+    @Override
+    public void removeRow(String dbName, String tableName, String uuid) {
+
+    }
+
+    @Override
+    public void updateOvsdbStore(String dbName, String tableName, String uuid, Row row) {
+
+    }
+
+    @Override
+    public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
+        return null;
+    }
+
+    @Override
+    public void disconnect() {
+
+    }
+
+    @Override
+    public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<List<String>> echo() {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema, String monitorId) {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<List<String>> listDbs() {
+        return null;
+    }
+
+    @Override
+    public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema, List<Operation> operations) {
+        return null;
+    }
+}
diff --git a/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java b/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java
new file mode 100644
index 0000000..902113a
--- /dev/null
+++ b/ovsdb/api/src/test/java/org/onosproject/ovsdb/controller/driver/OvsdbControllerAdapter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.ovsdb.controller.driver;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbEventListener;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.onosproject.ovsdb.controller.OvsdbNodeListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Test Adapter for OvsdbController.
+ */
+public class OvsdbControllerAdapter implements OvsdbController {
+    protected ConcurrentHashMap<OvsdbNodeId, OvsdbClientServiceAdapter> ovsdbClients =
+            new ConcurrentHashMap<OvsdbNodeId, OvsdbClientServiceAdapter>();
+
+    @Override
+    public void addNodeListener(OvsdbNodeListener listener) {
+
+    }
+
+    @Override
+    public void removeNodeListener(OvsdbNodeListener listener) {
+
+    }
+
+    @Override
+    public void addOvsdbEventListener(OvsdbEventListener listener) {
+
+    }
+
+    @Override
+    public void removeOvsdbEventListener(OvsdbEventListener listener) {
+
+    }
+
+    @Override
+    public List<OvsdbNodeId> getNodeIds() {
+        long port = 6653;
+        return new ArrayList<OvsdbNodeId>(Arrays.asList(
+                new OvsdbNodeId(IpAddress.valueOf("127.0.0.1"), port)));
+    }
+
+    @Override
+    public OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId) {
+        return ovsdbClients.get(nodeId);
+    }
+
+    @Override
+    public void connect(IpAddress ip, TpPort port) {
+
+    }
+}
diff --git a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
index beeaa9c..c2cbbf8 100644
--- a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
+++ b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java
@@ -15,18 +15,8 @@
  */
 package org.onosproject.ovsdb.controller.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.math.BigInteger;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ExecutionException;
-
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -68,7 +58,17 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import java.math.BigInteger;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * The implementation of OvsdbController.
@@ -134,8 +134,7 @@
 
     @Override
     public List<OvsdbNodeId> getNodeIds() {
-        // TODO Auto-generated method stub
-        return null;
+        return ImmutableList.copyOf(ovsdbClients.keySet());
     }
 
     @Override
@@ -210,8 +209,8 @@
      * Processes table updates.
      *
      * @param clientService OvsdbClientService instance
-     * @param updates TableUpdates instance
-     * @param dbName ovsdb database name
+     * @param updates       TableUpdates instance
+     * @param dbName        ovsdb database name
      */
     private void processTableUpdates(OvsdbClientService clientService,
                                      TableUpdates updates, String dbName)
@@ -242,8 +241,8 @@
                         Row row = clientService.getRow(OvsdbConstant.DATABASENAME, tableName, uuid.value());
                         dispatchInterfaceEvent(clientService,
                                                row,
-                                          OvsdbEvent.Type.PORT_REMOVED,
-                                          dbSchema);
+                                               OvsdbEvent.Type.PORT_REMOVED,
+                                               dbSchema);
                     }
                     clientService.removeRow(dbName, tableName, uuid.value());
                 }
@@ -255,10 +254,10 @@
      * Dispatches event to the north.
      *
      * @param clientService OvsdbClientService instance
-     * @param newRow a new row
-     * @param oldRow an old row
-     * @param eventType type of event
-     * @param dbSchema ovsdb database schema
+     * @param newRow        a new row
+     * @param oldRow        an old row
+     * @param eventType     type of event
+     * @param dbSchema      ovsdb database schema
      */
     private void dispatchInterfaceEvent(OvsdbClientService clientService,
                                         Row row,
@@ -283,13 +282,13 @@
         }
 
         EventSubject eventSubject = new DefaultEventSubject(MacAddress.valueOf(
-                                                                               macAndIfaceId[0]),
+                macAndIfaceId[0]),
                                                             new HashSet<IpAddress>(),
                                                             new OvsdbPortName(intf
-                                                                    .getName()),
+                                                                                      .getName()),
                                                             new OvsdbPortNumber(localPort),
                                                             new OvsdbDatapathId(Long
-                                                                    .toString(dpid)),
+                                                                                        .toString(dpid)),
                                                             new OvsdbPortType(portType),
                                                             new OvsdbIfaceId(macAndIfaceId[1]));
         for (OvsdbEventListener listener : ovsdbEventListener) {
@@ -315,7 +314,7 @@
 
         String attachedMac = externalIds.get(OvsdbConstant.EXTERNAL_ID_VM_MAC);
         if (attachedMac == null) {
-            log.warn("The attachedMac is null");
+            log.debug("The attachedMac is null"); //FIXME why always null?
             return null;
         }
         String ifaceid = externalIds
@@ -324,7 +323,7 @@
             log.warn("The ifaceid is null");
             return null;
         }
-        return new String[] {attachedMac, ifaceid};
+        return new String[]{attachedMac, ifaceid};
     }
 
     /**
@@ -349,7 +348,7 @@
      * Gets datapathid from table bridge.
      *
      * @param clientService OvsdbClientService instance
-     * @param dbSchema ovsdb database schema
+     * @param dbSchema      ovsdb database schema
      * @return datapathid the bridge datapathid
      */
     private long getDataPathid(OvsdbClientService clientService,
diff --git a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
index 3326922..0060960 100644
--- a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
+++ b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/notation/Row.java
@@ -15,20 +15,21 @@
  */
 package org.onosproject.ovsdb.rfc.notation;
 
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.Maps;
 
 import java.util.Collection;
 import java.util.Map;
 import java.util.Objects;
 
-import com.google.common.collect.Maps;
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Row is the basic element of the OpenVswitch's table.
  */
 public final class Row {
     private String tableName;
+    private UUID uuid;
     private Map<String, Column> columns;
 
     /**
@@ -40,9 +41,11 @@
 
     /**
      * Row constructor.
+     *
      * @param tableName table name
      */
-    public Row(String tableName) {
+    @Deprecated
+    private Row(String tableName) {
         checkNotNull(tableName, "tableName cannot be null");
         this.tableName = tableName;
         this.columns = Maps.newHashMap();
@@ -50,18 +53,22 @@
 
     /**
      * Row constructor.
+     *
      * @param tableName table name
-     * @param columns Map of Column entity
+     * @param columns   Map of Column entity
      */
-    public Row(String tableName, Map<String, Column> columns) {
+    public Row(String tableName, UUID uuid, Map<String, Column> columns) {
         checkNotNull(tableName, "table name cannot be null");
+        checkNotNull(uuid, "uuid cannot be null");
         checkNotNull(columns, "columns cannot be null");
         this.tableName = tableName;
+        this.uuid = uuid;
         this.columns = columns;
     }
 
     /**
      * Returns tableName.
+     *
      * @return tableName
      */
     public String tableName() {
@@ -70,6 +77,7 @@
 
     /**
      * Set tableName value.
+     *
      * @param tableName table name
      */
     public void setTableName(String tableName) {
@@ -77,7 +85,26 @@
     }
 
     /**
+     * Returns uuid.
+     *
+     * @return uuid
+     */
+    public UUID uuid() {
+        return uuid;
+    }
+
+    /**
+     * Sets uuid value.
+     *
+     * @param uuid new uuid
+     */
+    public void setUuid(UUID uuid) {
+        this.uuid = uuid;
+    }
+
+    /**
      * Returns Column by ColumnSchema.
+     *
      * @param columnName column name
      * @return Column
      */
@@ -87,6 +114,7 @@
 
     /**
      * Returns Collection of Column.
+     *
      * @return Collection of Column
      */
     public Collection<Column> getColumns() {
@@ -95,8 +123,9 @@
 
     /**
      * add Column.
+     *
      * @param columnName column name
-     * @param data Column entity
+     * @param data       Column entity
      */
     public void addColumn(String columnName, Column data) {
         this.columns.put(columnName, data);
diff --git a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
index bd589f0..0b5ffef 100644
--- a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
+++ b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/Bridge.java
@@ -15,16 +15,17 @@
  */
 package org.onosproject.ovsdb.rfc.table;
 
-import java.util.Map;
-import java.util.Set;
-
 import org.onosproject.ovsdb.rfc.notation.Column;
+import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
 import org.onosproject.ovsdb.rfc.notation.Row;
 import org.onosproject.ovsdb.rfc.notation.UUID;
 import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
 import org.onosproject.ovsdb.rfc.tableservice.AbstractOvsdbTableService;
 import org.onosproject.ovsdb.rfc.tableservice.ColumnDescription;
 
+import java.util.Map;
+import java.util.Set;
+
 /**
  * This class provides operations of Bridge Table.
  */
@@ -351,7 +352,7 @@
      * of attributes.
      * @param controller the column data which column name is "controller"
      */
-    public void setController(Set<UUID> controller) {
+    public void setController(OvsdbSet controller) {
         ColumnDescription columndesc = new ColumnDescription(
                                                              BridgeColumn.CONTROLLER
                                                                      .columnName(),
diff --git a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
index c1ae7c7..f5bd860 100644
--- a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
+++ b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/table/TableGenerator.java
@@ -37,6 +37,7 @@
      * @param tableName table name
      * @return Object table entity
      */
+    //FIXME change the name, it creates a row object, such as a controller.
     public static Object createTable(DatabaseSchema dbSchema,
                                      OvsdbTable tableName) {
         Row row = new Row();
diff --git a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
index 9744fb4..1dcf48f 100644
--- a/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
+++ b/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
@@ -15,12 +15,11 @@
  */
 package org.onosproject.ovsdb.rfc.utils;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.onosproject.ovsdb.rfc.exception.AbnormalJsonNodeException;
 import org.onosproject.ovsdb.rfc.exception.UnsupportedException;
 import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
@@ -41,11 +40,11 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * JsonNode utility class. convert JsonNode into Object.
@@ -247,7 +246,7 @@
         validateJsonNode(rowsNode, "rows");
         ArrayList<Row> rows = Lists.newArrayList();
         for (JsonNode rowNode : rowsNode.get("rows")) {
-            rows.add(createRow(tableSchema, rowNode));
+            rows.add(createRow(tableSchema, null, rowNode)); //FIXME null will throw exception
         }
         return rows;
     }
@@ -285,8 +284,8 @@
             UUID uuid = UUID.uuid(uuidStr);
             JsonNode newR = oldNewRow.getValue().get("new");
             JsonNode oldR = oldNewRow.getValue().get("old");
-            Row newRow = newR != null ? createRow(tableSchema, newR) : null;
-            Row oldRow = oldR != null ? createRow(tableSchema, oldR) : null;
+            Row newRow = newR != null ? createRow(tableSchema, uuid, newR) : null;
+            Row oldRow = oldR != null ? createRow(tableSchema, uuid, oldR) : null;
             RowUpdate rowUpdate = new RowUpdate(uuid, oldRow, newRow);
             rows.put(uuid, rowUpdate);
         }
@@ -299,7 +298,7 @@
      * @param rowNode JsonNode
      * @return Row
      */
-    private static Row createRow(TableSchema tableSchema, JsonNode rowNode) {
+    private static Row createRow(TableSchema tableSchema, UUID uuid, JsonNode rowNode) {
         if (tableSchema == null) {
             return null;
         }
@@ -314,7 +313,7 @@
                 columns.put(columnName, new Column(columnName, obj));
             }
         }
-        return new Row(tableSchema.name(), columns);
+        return new Row(tableSchema.name(), uuid, columns);
     }
 
 }
diff --git a/tools/test/cells/andrea b/tools/test/cells/andrea
index 0d93b18..1f9f22f 100644
--- a/tools/test/cells/andrea
+++ b/tools/test/cells/andrea
@@ -8,4 +8,4 @@
 
 export OCT=$OC1
 export ONOS_USE_SSH=true
-export ONOS_APPS=drivers,openflow,proxyarp,mobility
+export ONOS_APPS=drivers,openflow,proxyarp,ovsdb