org.opendaylight.ovsdb.plugin.ConfigurationService.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.ovsdb.plugin.ConfigurationService.java

Source

/*
 * Copyright (C) 2013 Red Hat, Inc.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Authors : Madhu Venugopal, Brent Salisbury, Keith Burns
 */
package org.opendaylight.ovsdb.plugin;

import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.opendaylight.controller.sal.connection.ConnectionConstants;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.ovsdb.lib.database.OVSInstance;
import org.opendaylight.ovsdb.lib.database.OvsdbType;
import org.opendaylight.ovsdb.lib.message.TransactBuilder;
import org.opendaylight.ovsdb.lib.message.operations.DeleteOperation;
import org.opendaylight.ovsdb.lib.message.operations.InsertOperation;
import org.opendaylight.ovsdb.lib.message.operations.MutateOperation;
import org.opendaylight.ovsdb.lib.message.operations.Operation;
import org.opendaylight.ovsdb.lib.message.operations.OperationResult;
import org.opendaylight.ovsdb.lib.message.operations.UpdateOperation;
import org.opendaylight.ovsdb.lib.notation.Condition;
import org.opendaylight.ovsdb.lib.notation.Function;
import org.opendaylight.ovsdb.lib.notation.Mutation;
import org.opendaylight.ovsdb.lib.notation.Mutator;
import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.table.Bridge;
import org.opendaylight.ovsdb.lib.table.Controller;
import org.opendaylight.ovsdb.lib.table.IPFIX;
import org.opendaylight.ovsdb.lib.table.Interface;
import org.opendaylight.ovsdb.lib.table.Manager;
import org.opendaylight.ovsdb.lib.table.Mirror;
import org.opendaylight.ovsdb.lib.table.NetFlow;
import org.opendaylight.ovsdb.lib.table.Open_vSwitch;
import org.opendaylight.ovsdb.lib.table.Port;
import org.opendaylight.ovsdb.lib.table.Qos;
import org.opendaylight.ovsdb.lib.table.Queue;
import org.opendaylight.ovsdb.lib.table.SFlow;
import org.opendaylight.ovsdb.lib.table.SSL;
import org.opendaylight.ovsdb.lib.table.internal.Table;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ListenableFuture;

public class ConfigurationService
        implements IPluginInBridgeDomainConfigService, OVSDBConfigService, CommandProvider {
    private static final Logger logger = LoggerFactory.getLogger(ConfigurationService.class);

    IConnectionServiceInternal connectionService;
    InventoryServiceInternal inventoryServiceInternal;
    boolean forceConnect = false;

    void init() {
    }

    /**
     * Function called by the dependency manager when at least one dependency
     * become unsatisfied or when the component is shutting down because for
     * example bundle is being stopped.
     *
     */
    void destroy() {
    }

    /**
     * Function called by dependency manager after "init ()" is called and after
     * the services provided by the class are registered in the service registry
     *
     */
    void start() {
        registerWithOSGIConsole();
    }

    private void registerWithOSGIConsole() {
        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
        bundleContext.registerService(CommandProvider.class.getName(), this, null);
    }

    /**
     * Function called by the dependency manager before the services exported by
     * the component are unregistered, this will be followed by a "destroy ()"
     * calls
     *
     */
    void stop() {
    }

    public void setConnectionServiceInternal(IConnectionServiceInternal connectionService) {
        this.connectionService = connectionService;
    }

    public void unsetConnectionServiceInternal(IConnectionServiceInternal connectionService) {
        if (this.connectionService == connectionService) {
            this.connectionService = null;
        }
    }

    public void setInventoryServiceInternal(InventoryServiceInternal inventoryServiceInternal) {
        this.inventoryServiceInternal = inventoryServiceInternal;
    }

    public void unsetInventoryServiceInternal(InventoryServiceInternal inventoryServiceInternal) {
        if (this.inventoryServiceInternal == inventoryServiceInternal) {
            this.inventoryServiceInternal = null;
        }
    }

    private Connection getConnection(Node node) {
        Connection connection = connectionService.getConnection(node);
        if (connection == null || !connection.getChannel().isActive()) {
            return null;
        }

        return connection;
    }

    /**
     * Add a new bridge
     * @param node Node serving this configuration service
     * @param bridgeIdentifier String representation of a Bridge Connector
     * @return Bridge Connector configurations
     */
    @Override
    public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }

            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());
            String newBridge = "new_bridge";
            String newInterface = "new_interface";
            String newPort = "new_port";
            String newSwitch = "new_switch";

            Operation addSwitchRequest = null;

            if (ovsTable != null) {
                String ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
                UUID bridgeUuidPair = new UUID(newBridge);
                Mutation bm = new Mutation("bridges", Mutator.INSERT, bridgeUuidPair);
                List<Mutation> mutations = new ArrayList<Mutation>();
                mutations.add(bm);

                UUID uuid = new UUID(ovsTableUUID);
                Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
                List<Condition> where = new ArrayList<Condition>();
                where.add(condition);
                addSwitchRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);
            } else {
                Open_vSwitch ovsTableRow = new Open_vSwitch();
                OvsDBSet<UUID> bridges = new OvsDBSet<UUID>();
                UUID bridgeUuidPair = new UUID(newBridge);
                bridges.add(bridgeUuidPair);
                ovsTableRow.setBridges(bridges);
                addSwitchRequest = new InsertOperation(Open_vSwitch.NAME.getName(), newSwitch, ovsTableRow);
            }

            Bridge bridgeRow = new Bridge();
            bridgeRow.setName(bridgeIdentifier);
            OvsDBSet<UUID> ports = new OvsDBSet<UUID>();
            UUID port = new UUID(newPort);
            ports.add(port);
            bridgeRow.setPorts(ports);
            InsertOperation addBridgeRequest = new InsertOperation(Bridge.NAME.getName(), newBridge, bridgeRow);

            Port portRow = new Port();
            portRow.setName(bridgeIdentifier);
            OvsDBSet<UUID> interfaces = new OvsDBSet<UUID>();
            UUID interfaceid = new UUID(newInterface);
            interfaces.add(interfaceid);
            portRow.setInterfaces(interfaces);
            InsertOperation addPortRequest = new InsertOperation(Port.NAME.getName(), newPort, portRow);

            Interface interfaceRow = new Interface();
            interfaceRow.setName(bridgeIdentifier);
            interfaceRow.setType("internal");
            InsertOperation addIntfRequest = new InsertOperation(Interface.NAME.getName(), newInterface,
                    interfaceRow);

            /* Update config version */
            String ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
            Mutation bm = new Mutation("next_cfg", Mutator.SUM, 1);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(ovsTableUUID);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            MutateOperation updateCfgVerRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where,
                    mutations);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addSwitchRequest, addIntfRequest,
                    addPortRequest, addBridgeRequest, updateCfgVerRequest)));

            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();
            Status status = new Status(StatusCode.SUCCESS);
            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeIdentifier,
                        result.getError(), result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            if (status.isSuccess()) {
                setBridgeOFController(node, bridgeIdentifier);
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in createBridgeDomain(): ", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    /**
     * Create a Port Attached to a Bridge
     * Ex. ovs-vsctl add-port br0 vif0
     * @param node Node serving this configuration service
     * @param bridgeIdentifier String representation of a Bridge Domain
     * @param portIdentifier String representation of a user defined Port Name
     */
    @Override
    public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
            Map<ConfigConstants, Object> configs) {
        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }
            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }
            if (connection != null) {
                Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
                String newBridge = "new_bridge";
                String newInterface = "new_interface";
                String newPort = "new_port";

                if (brTable != null) {
                    Operation addBrMutRequest = null;
                    String brUuid = null;
                    for (String uuid : brTable.keySet()) {
                        Bridge bridge = (Bridge) brTable.get(uuid);
                        if (bridge.getName().contains(bridgeIdentifier)) {
                            brUuid = uuid;
                        }
                    }

                    UUID brUuidPair = new UUID(newPort);
                    Mutation bm = new Mutation("ports", Mutator.INSERT, brUuidPair);
                    List<Mutation> mutations = new ArrayList<Mutation>();
                    mutations.add(bm);

                    UUID uuid = new UUID(brUuid);
                    Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
                    List<Condition> where = new ArrayList<Condition>();
                    where.add(condition);
                    addBrMutRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

                    OvsDBMap<String, String> options = null;
                    String type = null;
                    OvsDBSet<BigInteger> tags = null;
                    if (configs != null) {
                        type = (String) configs.get(ConfigConstants.TYPE);
                        Map<String, String> customConfigs = (Map<String, String>) configs
                                .get(ConfigConstants.CUSTOM);
                        if (customConfigs != null) {
                            options = new OvsDBMap<String, String>();
                            for (String customConfig : customConfigs.keySet()) {
                                options.put(customConfig, customConfigs.get(customConfig));
                            }
                        }
                    }

                    Interface interfaceRow = new Interface();
                    interfaceRow.setName(portIdentifier);

                    if (type != null) {
                        if (type.equalsIgnoreCase(OvsdbType.PortType.TUNNEL.name())) {
                            interfaceRow.setType((String) configs.get(ConfigConstants.TUNNEL_TYPE));
                            if (options == null)
                                options = new OvsDBMap<String, String>();
                            options.put("remote_ip", (String) configs.get(ConfigConstants.DEST_IP));
                        } else if (type.equalsIgnoreCase(OvsdbType.PortType.VLAN.name())) {
                            tags = new OvsDBSet<BigInteger>();
                            tags.add(BigInteger
                                    .valueOf(Integer.parseInt((String) configs.get(ConfigConstants.VLAN))));
                        } else if (type.equalsIgnoreCase(OvsdbType.PortType.PATCH.name())) {
                            interfaceRow.setType(type.toLowerCase());
                        }
                    }
                    if (options != null) {
                        interfaceRow.setOptions(options);
                    }

                    InsertOperation addIntfRequest = new InsertOperation(Interface.NAME.getName(), newInterface,
                            interfaceRow);

                    Port portRow = new Port();
                    portRow.setName(portIdentifier);
                    if (tags != null)
                        portRow.setTag(tags);
                    OvsDBSet<UUID> interfaces = new OvsDBSet<UUID>();
                    UUID interfaceid = new UUID(newInterface);
                    interfaces.add(interfaceid);
                    portRow.setInterfaces(interfaces);
                    InsertOperation addPortRequest = new InsertOperation(Port.NAME.getName(), newPort, portRow);

                    TransactBuilder transaction = new TransactBuilder();
                    transaction.addOperations(new ArrayList<Operation>(
                            Arrays.asList(addBrMutRequest, addPortRequest, addIntfRequest)));

                    ListenableFuture<List<OperationResult>> transResponse = connection.getRpc()
                            .transact(transaction);
                    List<OperationResult> tr = transResponse.get();
                    List<Operation> requests = transaction.getRequests();
                    Status status = new Status(StatusCode.SUCCESS);
                    for (int i = 0; i < tr.size(); i++) {
                        if (i < requests.size())
                            requests.get(i).setResult(tr.get(i));
                        if (tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                            OperationResult result = tr.get(i);
                            status = new Status(StatusCode.BADREQUEST,
                                    result.getError() + " : " + result.getDetails());
                        }
                    }

                    if (tr.size() > requests.size()) {
                        OperationResult result = tr.get(tr.size() - 1);
                        logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeIdentifier,
                                result.getError(), result.getDetails());
                        status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                    }
                    return status;
                }
                return new Status(StatusCode.INTERNALERROR);
            }
        } catch (Exception e) {
            logger.error("Error in addPort()", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    /**
     * Implements the OVS Connection for Managers
     *
     * @param node Node serving this configuration service
     * @param managerip String Representing IP and connection types
     */
    @SuppressWarnings("unchecked")
    public boolean setManager(Node node, String managerip) {
        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return false;
            }
            Connection connection = this.getConnection(node);
            if (connection == null) {
                return false;
            }

            if (connection != null) {
                String newmanager = "new_manager";

                OVSInstance instance = OVSInstance.monitorOVS(connection);

                Map ovsoutter = new LinkedHashMap();
                Map ovsinner = new LinkedHashMap();
                ArrayList ovsalist1 = new ArrayList();
                ArrayList ovsalist2 = new ArrayList();
                ArrayList ovsalist3 = new ArrayList();
                ArrayList ovsalist4 = new ArrayList();

                //OVS Table Update
                ovsoutter.put("where", ovsalist1);
                ovsalist1.add(ovsalist2);
                ovsalist2.add("_uuid");
                ovsalist2.add("==");
                ovsalist2.add(ovsalist3);
                ovsalist3.add("uuid");
                ovsalist3.add(instance.getUuid());
                ovsoutter.put("op", "update");
                ovsoutter.put("table", "Open_vSwitch");
                ovsoutter.put("row", ovsinner);
                ovsinner.put("manager_options", ovsalist4);
                ovsalist4.add("named-uuid");
                ovsalist4.add(newmanager);

                Map mgroutside = new LinkedHashMap();
                Map mgrinside = new LinkedHashMap();

                //Manager Table Insert
                mgroutside.put("uuid-name", newmanager);
                mgroutside.put("op", "insert");
                mgroutside.put("table", "Manager");
                mgroutside.put("row", mgrinside);
                mgrinside.put("target", managerip);

                Object[] params = { "Open_vSwitch", ovsoutter, mgroutside };
                OvsdbMessage msg = new OvsdbMessage("transact", params);

                //connection.sendMessage(msg);

            }
        } catch (Exception e) {
            logger.error("Error in setManager(): ", e);
        }
        return true;
    }

    @Override
    public Status addBridgeDomainConfig(Node node, String bridgeIdentfier, Map<ConfigConstants, Object> configs) {
        String mgmt = (String) configs.get(ConfigConstants.MGMT);
        if (mgmt != null) {
            if (setManager(node, mgmt))
                return new Status(StatusCode.SUCCESS);
        }
        return new Status(StatusCode.BADREQUEST);
    }

    @Override
    public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
            Map<ConfigConstants, Object> configs) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {

        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }

            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
            Operation delPortRequest = null;
            String brUuid = null;
            String portUuid = null;
            if (brTable != null) {
                for (String uuid : brTable.keySet()) {
                    Bridge bridge = (Bridge) brTable.get(uuid);
                    if (bridge.getName().contains(bridgeIdentifier)) {
                        brUuid = uuid;
                    }
                }
            }
            if (portTable != null) {
                for (String uuid : portTable.keySet()) {
                    Port port = (Port) portTable.get(uuid);
                    if (port.getName().contains(portIdentifier)) {
                        portUuid = uuid;
                    }
                }
            }

            UUID portUuidPair = new UUID(portUuid);
            Mutation bm = new Mutation("ports", Mutator.DELETE, portUuidPair);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(brUuid);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            delPortRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delPortRequest)));

            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();
            Status status = new Status(StatusCode.SUCCESS);
            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeIdentifier,
                        result.getError(), result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in deletePort()", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    @Override
    public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier, String portIdentifier) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
            Map<ConfigConstants, Object> configs) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
            Map<ConfigConstants, Object> configs) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {

        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }
            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }
            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            Operation delBrRequest = null;
            String ovsUuid = null;
            String brUuid = null;

            if (brTable != null) {
                for (String uuid : brTable.keySet()) {
                    Bridge bridge = (Bridge) brTable.get(uuid);
                    if (bridge.getName().contains(bridgeIdentifier)) {
                        brUuid = uuid;
                    }
                }
            }
            if (ovsTable != null) {
                ovsUuid = (String) ovsTable.keySet().toArray()[0];
            }
            UUID bridgeUuidPair = new UUID(brUuid);
            Mutation bm = new Mutation("bridges", Mutator.DELETE, bridgeUuidPair);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(ovsUuid);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            delBrRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delBrRequest)));

            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();
            Status status = new Status(StatusCode.SUCCESS);
            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error deleting Bridge : {}\n Error : {}\n Details : {}", bridgeIdentifier,
                        result.getError(), result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in deleteBridgeDomain(): ", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    @Override
    public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<String> getBridgeDomains(Node node) {
        List<String> brlist = new ArrayList<String>();
        Map<String, Table<?>> brTableCache = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
        if (brTableCache != null) {
            for (String uuid : brTableCache.keySet()) {
                Bridge bridge = (Bridge) brTableCache.get(uuid);
                brlist.add(bridge.getName());
            }
        }
        return brlist;
    }

    @Override
    public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
        return null;
    }

    Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
        if (connectionService == null) {
            logger.error("Couldn't refer to the ConnectionService");
            return false;
        }

        try {
            Map<String, Table<?>> brTableCache = inventoryServiceInternal.getTableCache(node,
                    Bridge.NAME.getName());
            for (String uuid : brTableCache.keySet()) {
                Bridge bridge = (Bridge) brTableCache.get(uuid);
                if (bridge.getName().contains(bridgeIdentifier)) {
                    return connectionService.setOFController(node, uuid);
                }
            }
        } catch (Exception e) {
            logger.error("Error in setBridgeOFController()", e);
        }
        return false;
    }

    @Override
    public StatusWithUuid insertRow(Node node, String tableName, String parent_uuid, Table<?> row) {
        logger.debug("tableName : {}, parent_uuid : {} Row : {}", tableName, parent_uuid, row.toString());
        StatusWithUuid statusWithUUID = null;

        // Schema based Table handling will help fix this static Table handling.

        if (row.getTableName().getName().equalsIgnoreCase("Bridge")) {
            statusWithUUID = insertBridgeRow(node, parent_uuid, (Bridge) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Capability")) {
            return new StatusWithUuid(StatusCode.NOTIMPLEMENTED,
                    "Insert operation for this Table is not implemented yet.");
        } else if (row.getTableName().getName().equalsIgnoreCase("Controller")) {
            statusWithUUID = insertControllerRow(node, parent_uuid, (Controller) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Interface")) {
            statusWithUUID = insertInterfaceRow(node, parent_uuid, (Interface) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Manager")) {
            statusWithUUID = insertManagerRow(node, parent_uuid, (Manager) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Mirror")) {
            statusWithUUID = insertMirrorRow(node, parent_uuid, (Mirror) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("NetFlow")) {
            statusWithUUID = insertNetFlowRow(node, parent_uuid, (NetFlow) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Open_vSwitch")) {
            statusWithUUID = insertOpen_vSwitchRow(node, (Open_vSwitch) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Port")) {
            statusWithUUID = insertPortRow(node, parent_uuid, (Port) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("QoS")) {
            statusWithUUID = insertQosRow(node, parent_uuid, (Qos) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("Queue")) {
            statusWithUUID = insertQueueRow(node, parent_uuid, (Queue) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("sFlow")) {
            statusWithUUID = insertSflowRow(node, parent_uuid, (SFlow) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("IPFIX")) {
            statusWithUUID = insertIpFixRow(node, parent_uuid, (IPFIX) row);
        } else if (row.getTableName().getName().equalsIgnoreCase("SSL")) {
            statusWithUUID = insertSSLRow(node, parent_uuid, (SSL) row);
        }
        return statusWithUUID;
    }

    @Override
    public Status updateRow(Node node, String tableName, String parentUUID, String rowUUID, Table<?> row) {
        try {
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }

            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());

            if (ovsTable == null) {
                return new Status(StatusCode.NOTFOUND,
                        "There are no Open_vSwitch instance in the Open_vSwitch table");
            }

            UUID uuid = new UUID(rowUUID);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            Operation updateRequest = new UpdateOperation(tableName, where, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(updateRequest)));

            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();
            Status status = new Status(StatusCode.SUCCESS);
            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error Updating Row : {}/{}\n Error : {}\n Details : {}", tableName, row,
                        result.getError(), result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            if (status.isSuccess()) {
                status = new Status(StatusCode.SUCCESS);
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in updateRow(): ", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    @Override
    public Status deleteRow(Node node, String tableName, String uuid) {
        if (tableName.equalsIgnoreCase("Bridge")) {
            return deleteBridgeRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Capbility")) {
            return new Status(StatusCode.NOTIMPLEMENTED, "Delete operation for this Table is not implemented yet.");
        } else if (tableName.equalsIgnoreCase("Controller")) {
            return deleteControllerRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Interface")) {
            return deleteInterfaceRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Manager")) {
            return deleteManagerRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Mirror")) {
            return deleteMirrorRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("NetFlow")) {
            return deleteNetFlowRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Open_vSwitch")) {
            return deleteOpen_vSwitchRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Port")) {
            return deletePortRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("QoS")) {
            return deleteQosRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("Queue")) {
            return deleteQueueRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("sFlow")) {
            return deleteSflowRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("IPFIX")) {
            return deleteIpFixRow(node, uuid);
        } else if (tableName.equalsIgnoreCase("SSL")) {
            return deleteSSLRow(node, uuid);
        }
        return new Status(StatusCode.NOTFOUND, "Table " + tableName + " not supported");
    }

    @Override
    public ConcurrentMap<String, Table<?>> getRows(Node node, String tableName) throws Exception {
        try {
            if (inventoryServiceInternal == null) {
                throw new Exception("Inventory Service is Unavailable.");
            }
            ConcurrentMap<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node, tableName);
            return ovsTable;
        } catch (Exception e) {
            throw new Exception("Unable to read table due to " + e.getMessage());
        }
    }

    @Override
    public Table<?> getRow(Node node, String tableName, String uuid) throws Exception {
        try {
            if (inventoryServiceInternal == null) {
                throw new Exception("Inventory Service is Unavailable.");
            }
            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node, tableName);
            if (ovsTable == null)
                return null;
            return ovsTable.get(uuid);
        } catch (Exception e) {
            throw new Exception("Unable to read table due to " + e.getMessage());
        }
    }

    @Override
    public String getSerializedRows(Node node, String tableName) throws Exception {
        try {
            Map<String, Table<?>> ovsTable = this.getRows(node, tableName);
            if (ovsTable == null)
                return null;
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(ovsTable);
        } catch (Exception e) {
            throw new Exception("Unable to read table due to " + e.getMessage());
        }
    }

    @Override
    public String getSerializedRow(Node node, String tableName, String uuid) throws Exception {
        try {
            Table<?> row = this.getRow(node, tableName, uuid);
            if (row == null)
                return null;
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(row);
        } catch (Exception e) {
            throw new Exception("Unable to read table due to " + e.getMessage());
        }
    }

    @Override
    public List<String> getTables(Node node) {
        ConcurrentMap<String, ConcurrentMap<String, Table<?>>> cache = inventoryServiceInternal.getCache(node);
        if (cache == null)
            return null;
        return new ArrayList<String>(cache.keySet());
    }

    private StatusWithUuid insertBridgeRow(Node node, String open_VSwitch_uuid, Bridge bridgeRow) {

        String insertErrorMsg = "bridge";
        String rowName = bridgeRow.getName();

        try {
            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());

            if (ovsTable == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND,
                        "There are no Open_vSwitch instance in the Open_vSwitch table");
            }

            String newBridge = "new_bridge";

            Operation addSwitchRequest = null;

            String ovsTableUUID = open_VSwitch_uuid;
            if (ovsTableUUID == null)
                ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
            UUID bridgeUuid = new UUID(newBridge);
            Mutation bm = new Mutation("bridges", Mutator.INSERT, bridgeUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(ovsTableUUID);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addSwitchRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);

            InsertOperation addBridgeRequest = new InsertOperation(Bridge.NAME.getName(), newBridge, bridgeRow);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addSwitchRequest, addBridgeRequest)));

            int bridgeInsertIndex = transaction.getRequests().indexOf(addBridgeRequest);

            return _insertTableRow(node, transaction, bridgeInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertBridgeRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertPortRow(Node node, String bridge_uuid, Port portRow) {

        String insertErrorMsg = "port";
        String rowName = portRow.getName();

        try {
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(bridge_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + bridge_uuid + " Not found");
            }
            String newPort = "new_port";
            UUID portUUID = new UUID(newPort);
            Mutation bm = new Mutation("ports", Mutator.INSERT, portUUID);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(bridge_uuid);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            Operation addBrMutRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

            // Default OVS schema is to have 1 or more interface part of Bridge. Hence it is mandatory to
            // Insert an Interface in a Port add case

            String newInterface = "new_interface";
            Interface interfaceRow = new Interface();
            interfaceRow.setName(portRow.getName());
            InsertOperation addIntfRequest = new InsertOperation(Interface.NAME.getName(), newInterface,
                    interfaceRow);

            OvsDBSet<UUID> interfaces = new OvsDBSet<UUID>();
            UUID interfaceid = new UUID(newInterface);
            interfaces.add(interfaceid);
            portRow.setInterfaces(interfaces);

            InsertOperation addPortRequest = new InsertOperation(Port.NAME.getName(), newPort, portRow);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(
                    new ArrayList<Operation>(Arrays.asList(addBrMutRequest, addPortRequest, addIntfRequest)));
            int portInsertIndex = transaction.getRequests().indexOf(addPortRequest);

            return _insertTableRow(node, transaction, portInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertPortRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertInterfaceRow(Node node, String port_uuid, Interface interfaceRow) {

        String insertErrorMsg = "interface";
        String rowName = interfaceRow.getName();

        try {

            // Interface table must have entry in Port table, checking port table for port
            Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
            if (portTable == null || portTable.get(port_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Port with UUID " + port_uuid + " Not found");
            }
            // MUTATOR, need to insert the interface UUID to LIST of interfaces in PORT TABLE for port_uuid
            String newInterface = "new_interface";
            UUID interfaceUUID = new UUID(newInterface);
            Mutation portTableMutation = new Mutation("interfaces", Mutator.INSERT, interfaceUUID); // field name to append is "interfaces"
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(portTableMutation);

            // Create the Operation which will be used in Transact to perform the PORT TABLE mutation
            UUID uuid = new UUID(port_uuid);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            Operation addPortMutationRequest = new MutateOperation(Port.NAME.getName(), where, mutations);

            // Create the interface row request
            InsertOperation addIntfRequest = new InsertOperation(Interface.NAME.getName(), newInterface,
                    interfaceRow);

            // Transaction to insert/modify tables - validate using "sudo ovsdb-client dump" on host running OVSDB process
            TransactBuilder transaction = new TransactBuilder();
            transaction
                    .addOperations(new ArrayList<Operation>(Arrays.asList(addIntfRequest, addPortMutationRequest)));

            // Check the results. Iterates over the results of the Array of transaction Operations, and reports STATUS
            int interfaceInsertIndex = transaction.getRequests().indexOf(addIntfRequest);

            return _insertTableRow(node, transaction, interfaceInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertInterfaceRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertOpen_vSwitchRow(Node node, Open_vSwitch row) {
        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED,
                "Insert operation for this Table is not implemented yet.");
    }

    private StatusWithUuid insertControllerRow(Node node, String bridge_uuid, Controller row) {

        String insertErrorMsg = "controller";
        String rowName = row.getTableName().toString();

        try {

            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(bridge_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + bridge_uuid + " Not found");
            }

            Map<String, Table<?>> controllerCache = inventoryServiceInternal.getTableCache(node,
                    Controller.NAME.getName());

            String uuid_name = "new_controller";
            boolean controllerExists = false;
            if (controllerCache != null) {
                for (String uuid : controllerCache.keySet()) {
                    Controller controller = (Controller) controllerCache.get(uuid);
                    if (controller.getTarget().equals(row.getTarget())) {
                        uuid_name = uuid;
                        controllerExists = true;
                        break;
                    }
                }
            }

            UUID controllerUUID = new UUID(uuid_name);
            Mutation bm = new Mutation("controller", Mutator.INSERT, controllerUUID);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(bm);

            UUID uuid = new UUID(bridge_uuid);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            Operation addBrMutRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);
            InsertOperation addControllerRequest = null;

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperation(addBrMutRequest);
            int portInsertIndex = -1;
            if (!controllerExists) {
                addControllerRequest = new InsertOperation(Controller.NAME.getName(), uuid_name, row);
                transaction.addOperation(addControllerRequest);
                portInsertIndex = transaction.getRequests().indexOf(addControllerRequest);
            }

            StatusWithUuid status = _insertTableRow(node, transaction, portInsertIndex, insertErrorMsg, rowName);
            if (status.isSuccess() && controllerExists) {
                // We won't get the uuid from the transact, so we set it here
                status = new StatusWithUuid(status.getCode(), controllerUUID);
            }
            return status;

        } catch (Exception e) {
            logger.error("Error in insertControllerRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertSSLRow(Node node, String parent_uuid, SSL row) {
        String insertErrorMsg = "SSL";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());

            if (ovsTable == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND,
                        "There are no Open_vSwitch instance in the Open_vSwitch table");
            }

            String newSSL = "new_SSL";

            Operation addOpen_vSwitchRequest = null;

            String ovsTableUUID = parent_uuid;
            if (ovsTableUUID == null)
                ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
            UUID sslUuid = new UUID(newSSL);
            Mutation sslMutation = new Mutation("ssl", Mutator.INSERT, sslUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(sslMutation);

            UUID uuid = new UUID(ovsTableUUID);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addOpen_vSwitchRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);

            InsertOperation addSSLRequest = new InsertOperation(SSL.NAME.getName(), newSSL, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction
                    .addOperations(new ArrayList<Operation>(Arrays.asList(addSSLRequest, addOpen_vSwitchRequest)));

            int sslInsertIndex = transaction.getRequests().indexOf(addSSLRequest);

            return _insertTableRow(node, transaction, sslInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertSSLRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertIpFixRow(Node node, String parent_uuid, IPFIX row) {

        String insertErrorMsg = "ipfix";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(parent_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + parent_uuid + " Not found");
            }

            if (parent_uuid == null) {
                return new StatusWithUuid(StatusCode.BADREQUEST, "Require parent Bridge UUID.");
            }

            UUID uuid = new UUID(parent_uuid);
            String newIpFix = "new_ipfix";
            Operation addBridgeRequest = null;
            UUID ipfixUuid = new UUID(newIpFix);
            Mutation ipfixMutation = new Mutation("ipfix", Mutator.INSERT, ipfixUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(ipfixMutation);

            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addBridgeRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);
            InsertOperation addIpFixRequest = new InsertOperation(IPFIX.NAME.getName(), newIpFix, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addIpFixRequest, addBridgeRequest)));
            int ipfixInsertIndex = transaction.getRequests().indexOf(addIpFixRequest);

            return _insertTableRow(node, transaction, ipfixInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertInterfaceRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertSflowRow(Node node, String parent_uuid, SFlow row) {

        String insertErrorMsg = "sFlow";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(parent_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + parent_uuid + " Not found");
            }

            if (parent_uuid == null) {
                return new StatusWithUuid(StatusCode.BADREQUEST, "Require parent Bridge UUID.");
            }

            UUID uuid = new UUID(parent_uuid);

            String newSflow = "new_sflow";

            Operation addBridgeRequest = null;

            UUID sflowUuid = new UUID(newSflow);
            Mutation sflowMutation = new Mutation("sflow", Mutator.INSERT, sflowUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(sflowMutation);

            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addBridgeRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

            InsertOperation addSflowRequest = new InsertOperation(SFlow.NAME.getName(), newSflow, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addSflowRequest, addBridgeRequest)));

            int sflowInsertIndex = transaction.getRequests().indexOf(addSflowRequest);

            return _insertTableRow(node, transaction, sflowInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertInterfaceRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertQueueRow(Node node, String parent_uuid, Queue row) {
        String insertErrorMsg = "Queue";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> qosTable = inventoryServiceInternal.getTableCache(node, Qos.NAME.getName());
            if (qosTable == null || qosTable.get(parent_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "QoS with UUID " + parent_uuid + " Not found");
            }

            if (parent_uuid == null) {
                return new StatusWithUuid(StatusCode.BADREQUEST, "Require parent QoS UUID.");
            }

            // NOTE: Queue Table is "isroot" meaning it can have a hanging reference. This is different from
            // standing insertRow due to the parent column type being a map, where one of the items may not be known
            // at time of insert. Therefore this is a simple insert, rather than mutate/insert.
            String newQueue = "new_queue";
            InsertOperation addQueueRequest = new InsertOperation(Queue.NAME.getName(), newQueue, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addQueueRequest)));

            int queueInsertIndex = transaction.getRequests().indexOf(addQueueRequest);

            return _insertTableRow(node, transaction, queueInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertQueueRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertQosRow(Node node, String parent_uuid, Qos row) {
        String insertErrorMsg = "Qos";
        String rowName = row.NAME.getName();

        try {

            String newQos = "new_qos";

            // QoS Table "isroot" meaning it can have hanging references. If parent_uuid is not supplied in API call this becomes a simple
            // insert operation, rather than the typical mutate/insert parent/child insert.
            if (parent_uuid != null) {
                // Port (parent) table check for UUID existance.
                Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
                if (portTable == null || portTable.get(parent_uuid) == null) {
                    return new StatusWithUuid(StatusCode.NOTFOUND, "Port with UUID " + parent_uuid + " Not found");
                }

                UUID qosUuid = new UUID(newQos);
                Mutation qosMutation = new Mutation("qos", Mutator.INSERT, qosUuid);
                List<Mutation> mutations = new ArrayList<Mutation>();
                mutations.add(qosMutation);

                Operation addPortRequest = null;
                UUID uuid = new UUID(parent_uuid);
                Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
                List<Condition> where = new ArrayList<Condition>();
                where.add(condition);
                addPortRequest = new MutateOperation(Port.NAME.getName(), where, mutations);

                InsertOperation addQosRequest = new InsertOperation(Qos.NAME.getName(), newQos, row);

                TransactBuilder transaction = new TransactBuilder();
                transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addQosRequest, addPortRequest)));

                int qosInsertIndex = transaction.getRequests().indexOf(addQosRequest);

                return _insertTableRow(node, transaction, qosInsertIndex, insertErrorMsg, rowName);

            } else {
                InsertOperation addQosRequest = new InsertOperation(Qos.NAME.getName(), newQos, row);

                TransactBuilder transaction = new TransactBuilder();
                transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addQosRequest)));

                int qosInsertIndex = transaction.getRequests().indexOf(addQosRequest);

                return _insertTableRow(node, transaction, qosInsertIndex, insertErrorMsg, rowName);
            }

        } catch (Exception e) {
            logger.error("Error in insertQosRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertNetFlowRow(Node node, String parent_uuid, NetFlow row) {
        String insertErrorMsg = "netFlow";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(parent_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + parent_uuid + " Not found");
            }

            if (parent_uuid == null) {
                return new StatusWithUuid(StatusCode.BADREQUEST, "Require parent Bridge UUID.");
            }

            UUID uuid = new UUID(parent_uuid);
            String newNetflow = "new_netflow";

            Operation addBridgeRequest = null;

            UUID netFlowUuid = new UUID(newNetflow);
            Mutation netFlowMutation = new Mutation("netflow", Mutator.INSERT, netFlowUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(netFlowMutation);

            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addBridgeRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

            InsertOperation addNetflowRequest = new InsertOperation(NetFlow.NAME.getName(), newNetflow, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addNetflowRequest, addBridgeRequest)));

            int netflowInsertIndex = transaction.getRequests().indexOf(addNetflowRequest);

            return _insertTableRow(node, transaction, netflowInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertNetFlowRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertMirrorRow(Node node, String parent_uuid, Mirror row) {
        String insertErrorMsg = "mirror";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
            if (brTable == null || brTable.get(parent_uuid) == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID " + parent_uuid + " Not found");
            }

            if (parent_uuid == null) {
                return new StatusWithUuid(StatusCode.BADREQUEST, "Require parent Bridge UUID.");
            }

            UUID uuid = new UUID(parent_uuid);
            String newMirror = "new_mirror";

            Operation addBridgeRequest = null;

            UUID mirrorUuid = new UUID(newMirror);
            Mutation mirrorMutation = new Mutation("mirrors", Mutator.INSERT, mirrorUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(mirrorMutation);

            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addBridgeRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);

            InsertOperation addMirrorRequest = new InsertOperation(Mirror.NAME.getName(), newMirror, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addBridgeRequest, addMirrorRequest)));

            int mirrorInsertIndex = transaction.getRequests().indexOf(addMirrorRequest);

            return _insertTableRow(node, transaction, mirrorInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertMirrorRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid insertManagerRow(Node node, String parent_uuid, Manager row) {
        String insertErrorMsg = "manager";
        String rowName = row.NAME.getName();

        try {
            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node,
                    Open_vSwitch.NAME.getName());

            if (ovsTable == null) {
                return new StatusWithUuid(StatusCode.NOTFOUND,
                        "There are no Open_vSwitch instance in the Open_vSwitch table");
            }

            String newManager = "new_manager";

            Operation addSwitchRequest = null;

            String ovsTableUUID = parent_uuid;
            if (ovsTableUUID == null)
                ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
            UUID managerUuid = new UUID(newManager);
            Mutation managerMutation = new Mutation("manager_options", Mutator.INSERT, managerUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(managerMutation);

            UUID uuid = new UUID(ovsTableUUID);
            Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            addSwitchRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);

            InsertOperation addManagerRequest = new InsertOperation(Manager.NAME.getName(), newManager, row);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addSwitchRequest, addManagerRequest)));

            int managerInsertIndex = transaction.getRequests().indexOf(addManagerRequest);

            return _insertTableRow(node, transaction, managerInsertIndex, insertErrorMsg, rowName);

        } catch (Exception e) {
            logger.error("Error in insertManagerRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private StatusWithUuid _insertTableRow(Node node, TransactBuilder transaction, Integer insertIndex,
            String insertErrorMsg, String rowName) {

        try {
            //Check for connection before calling RPC to perform transaction
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new StatusWithUuid(StatusCode.NOSERVICE);
            }

            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new StatusWithUuid(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();
            StatusWithUuid status = new StatusWithUuid(StatusCode.SUCCESS);
            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new StatusWithUuid(StatusCode.BADREQUEST,
                            result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error creating {} : {}\n Error : {}\n Details : {}", insertErrorMsg, rowName,
                        result.getError(), result.getDetails());
                status = new StatusWithUuid(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            if (status.isSuccess()) {
                if (insertIndex >= 0 && insertIndex < tr.size() && tr.get(insertIndex) != null) {
                    UUID uuid = tr.get(insertIndex).getUuid();
                    status = new StatusWithUuid(StatusCode.SUCCESS, uuid);
                } else {
                    // We can't get the uuid from the transact as the insertIndex is invalid or -1
                    // return null uuid.
                    status = new StatusWithUuid(StatusCode.SUCCESS, (UUID) null);
                }
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in _insertTableRow(): ", e);
        }
        return new StatusWithUuid(StatusCode.INTERNALERROR);
    }

    private Status deleteBridgeRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Open_vSwitch.NAME.getName();
        String childTableName = Bridge.NAME.getName();
        String parentColumn = "bridges";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deletePortRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = Port.NAME.getName();
        String parentColumn = "ports";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteInterfaceRow(Node node, String uuid) {
        // Since Port<-Interface tables have a 1:n relationship, need to test if this is the last interface
        // assigned to a port before attempting delete.
        Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
        Map<String, Table<?>> interfaceTable = inventoryServiceInternal.getTableCache(node,
                Interface.NAME.getName());
        // Check that the UUID exists
        if (portTable == null || interfaceTable == null || uuid == null || interfaceTable.get(uuid) == null) {
            return new Status(StatusCode.NOTFOUND, "");
        }

        // Since the above past, it's safe to use the generic _deleteTableRow method
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Port.NAME.getName();
        String childTableName = Interface.NAME.getName();
        String parentColumn = "interfaces";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteControllerRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = Controller.NAME.getName();
        String parentColumn = "controller";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteOpen_vSwitchRow(Node node, String uuid) {
        return new Status(StatusCode.NOTIMPLEMENTED, "delete operation for this Table is not implemented yet.");
    }

    private Status deleteSSLRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Open_vSwitch.NAME.getName();
        String childTableName = SSL.NAME.getName();
        String parentColumn = "ssl";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteSflowRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = SFlow.NAME.getName();
        String parentColumn = "sflow";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteIpFixRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = IPFIX.NAME.getName();
        String parentColumn = "ipfix";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteQueueRow(Node node, String uuid) {
        // Set up variables for _deleteRootTableRow()
        // This doesn't do a mutate on parent, but simply deletes row
        String childTableName = Queue.NAME.getName();

        return _deleteRootTableRow(node, uuid, childTableName);
    }

    private Status deleteQosRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Port.NAME.getName();
        String childTableName = Qos.NAME.getName();
        String parentColumn = "qos";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteNetFlowRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = NetFlow.NAME.getName();
        String parentColumn = "netflow";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteMirrorRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Bridge.NAME.getName();
        String childTableName = Mirror.NAME.getName();
        String parentColumn = "mirrors";
        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status deleteManagerRow(Node node, String uuid) {
        // Set up variables for generic _deleteTableRow()
        String parentTableName = Open_vSwitch.NAME.getName();
        String childTableName = Manager.NAME.getName();
        String parentColumn = "manager_options";

        return _deleteTableRow(node, uuid, parentTableName, childTableName, parentColumn);
    }

    private Status _deleteTableRow(Node node, String uuid, String parentTableName, String childTableName,
            String parentColumn) {
        try {
            // Check there is a connectionService
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }

            // Establish the connection
            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            // Remove from Parent and Child
            Map<String, Table<?>> parentTable = inventoryServiceInternal.getTableCache(node, parentTableName);
            Map<String, Table<?>> childTable = inventoryServiceInternal.getTableCache(node, childTableName);

            // Check that the UUID exists
            if (parentTable == null || childTable == null || uuid == null || childTable.get(uuid) == null) {
                return new Status(StatusCode.NOTFOUND, "");
            }

            // Initialise the actual request var
            Operation delRequest = null;

            // Prepare the mutator to remove the child UUID from the parentColumn list in the parent TABLE
            UUID rowUuid = new UUID(uuid);
            Mutation mutator = new Mutation(parentColumn, Mutator.DELETE, rowUuid);
            List<Mutation> mutations = new ArrayList<Mutation>();
            mutations.add(mutator);

            Status status = new Status(StatusCode.SUCCESS);

            // INCLUDES condition ensures that it captures all rows in the parent table (ie duplicates) that have the child UUID
            Condition condition = new Condition(parentColumn, Function.INCLUDES, rowUuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            delRequest = new MutateOperation(parentTableName, where, mutations);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delRequest)));

            // This executes the transaction.
            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);

            // Pull the responses
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();

            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error deleting: {}\n Error : {}\n Details : {}", uuid, result.getError(),
                        result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in _deleteTableRow", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    private Status _deleteRootTableRow(Node node, String uuid, String TableName) {
        try {
            // Check there is a connectionService
            if (connectionService == null) {
                logger.error("Couldn't refer to the ConnectionService");
                return new Status(StatusCode.NOSERVICE);
            }

            // Establish the connection
            Connection connection = this.getConnection(node);
            if (connection == null) {
                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
            }

            Map<String, Table<?>> table = inventoryServiceInternal.getTableCache(node, TableName);

            // Check that the UUID exists
            if (table == null || table.get(uuid) == null) {
                return new Status(StatusCode.NOTFOUND, "");
            }

            // Initialise the actual request var
            Operation delRequest = null;

            UUID rowUuid = new UUID(uuid);

            Status status = new Status(StatusCode.SUCCESS);

            Condition condition = new Condition("_uuid", Function.EQUALS, rowUuid);
            List<Condition> where = new ArrayList<Condition>();
            where.add(condition);
            delRequest = new DeleteOperation(TableName, where);

            TransactBuilder transaction = new TransactBuilder();
            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delRequest)));

            // This executes the transaction.
            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);

            // Pull the responses
            List<OperationResult> tr = transResponse.get();
            List<Operation> requests = transaction.getRequests();

            for (int i = 0; i < tr.size(); i++) {
                if (i < requests.size())
                    requests.get(i).setResult(tr.get(i));
                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                    OperationResult result = tr.get(i);
                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                }
            }

            if (tr.size() > requests.size()) {
                OperationResult result = tr.get(tr.size() - 1);
                logger.error("Error deleting: {}\n Error : {}\n Details : {}", uuid, result.getError(),
                        result.getDetails());
                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
            }
            return status;
        } catch (Exception e) {
            logger.error("Error in _deleteRootTableRow", e);
        }
        return new Status(StatusCode.INTERNALERROR);
    }

    public void _ovsconnect(CommandInterpreter ci) {
        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }

        String ovsdbserver = ci.nextArgument();
        if (ovsdbserver == null) {
            ci.println("Please enter valid IP-Address");
            return;
        }
        try {
            InetAddress.getByName(ovsdbserver);
        } catch (UnknownHostException e) {
            logger.error("Unable to resolve " + ovsdbserver, e);
            ci.println("Please enter valid IP-Address");
            return;
        }
        String port = ci.nextArgument();
        if (port == null) {
            port = "6634";
        }

        ci.println("connecting to ovsdb server : " + ovsdbserver + ":" + port + " ... ");
        Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
        params.put(ConnectionConstants.ADDRESS, ovsdbserver);
        params.put(ConnectionConstants.PORT, port);
        Node node = connectionService.connect(bridgeName, params);
        if (node != null)
            ci.println("Node Name: " + node.toString());
        else
            ci.println("Could not connect to Node");
    }

    public void _addBridge(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }
        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }
        Status status;

        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.createBridgeDomain(node, bridgeName, null);
        ci.println("Bridge creation status : " + status.toString());
    }

    public void _getBridgeDomains(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }

        List<String> brlist = new ArrayList<String>();
        Node node = Node.fromString(nodeName);
        brlist = this.getBridgeDomains(node);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        ci.println("Existing Bridges: " + brlist.toString());
    }

    public void _deleteBridgeDomain(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }
        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }
        Status status;
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.deleteBridgeDomain(node, bridgeName);
        ci.println("Bridge deletion status : " + status.toString());
    }

    public void _addPort(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }

        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }

        String portName = ci.nextArgument();
        if (portName == null) {
            ci.println("Please enter Port Name");
            return;
        }

        String type = ci.nextArgument();

        Map<String, String> configs = new HashMap<String, String>();
        while (true) {
            String configKey = ci.nextArgument();
            if (configKey == null)
                break;
            String configValue = ci.nextArgument();
            if (configValue == null)
                break;
            configs.put(configKey, configValue);
        }

        Map<ConfigConstants, Object> customConfigs = null;
        if (type != null) {
            customConfigs = new HashMap<ConfigConstants, Object>();
            customConfigs.put(ConfigConstants.TYPE, type);
        }

        if (configs.size() > 0) {
            if (customConfigs == null)
                customConfigs = new HashMap<ConfigConstants, Object>();
            customConfigs.put(ConfigConstants.CUSTOM, configs);
            ci.println(customConfigs.toString());
        }
        Status status;
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.addPort(node, bridgeName, portName, customConfigs);
        ci.println("Port creation status : " + status.toString());
    }

    public void _deletePort(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }

        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }

        String portName = ci.nextArgument();
        if (portName == null) {
            ci.println("Please enter Port Name");
            return;
        }

        Status status;
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.deletePort(node, bridgeName, portName);
        ci.println("Port deletion status : " + status.toString());
    }

    public void _addPortVlan(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }

        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }

        String portName = ci.nextArgument();
        if (portName == null) {
            ci.println("Please enter Port Name");
            return;
        }

        String vlan = ci.nextArgument();
        if (vlan == null) {
            ci.println("Please enter Valid Vlan");
            return;
        } else {
            try {
                Integer.parseInt(vlan);
            } catch (NumberFormatException e) {
                ci.println("Please enter Valid Vlan");
                return;
            }
        }

        Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
        configs.put(ConfigConstants.TYPE, "VLAN");
        configs.put(ConfigConstants.VLAN, vlan);

        Status status;
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.addPort(node, bridgeName, portName, configs);
        ci.println("Port creation status : " + status.toString());
    }

    public void _addTunnel(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }

        String bridgeName = ci.nextArgument();
        if (bridgeName == null) {
            ci.println("Please enter Bridge Name");
            return;
        }

        String portName = ci.nextArgument();
        if (portName == null) {
            ci.println("Please enter Port Name");
            return;
        }

        String tunnelType = ci.nextArgument();
        if (tunnelType == null) {
            ci.println("Please enter Tunnel Type");
            return;
        }

        String remoteIp = ci.nextArgument();
        if (remoteIp == null) {
            ci.println("Please enter valid Remote IP Address");
            return;
        }

        try {
            InetAddress.getByName(remoteIp);
        } catch (Exception e) {
            logger.error("Unable to resolve " + remoteIp, e);
            ci.println("Please enter valid Remote IP Address");
            return;
        }

        Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
        configs.put(ConfigConstants.TYPE, "TUNNEL");
        configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
        configs.put(ConfigConstants.DEST_IP, remoteIp);

        Status status;
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        status = this.addPort(node, bridgeName, portName, configs);
        ci.println("Port creation status : " + status.toString());
    }

    public void _printCache(CommandInterpreter ci) {
        String nodeName = ci.nextArgument();
        if (nodeName == null) {
            ci.println("Please enter Node Name");
            return;
        }
        Node node = Node.fromString(nodeName);
        if (node == null) {
            ci.println("Invalid Node");
            return;
        }
        inventoryServiceInternal.printCache(node);
    }

    public void _forceConnect(CommandInterpreter ci) {
        String force = ci.nextArgument();
        if (force.equalsIgnoreCase("YES")) {
            forceConnect = true;
        } else if (force.equalsIgnoreCase("NO")) {
            forceConnect = false;
        } else {
            ci.println("Please enter YES or NO.");
        }
        ci.println("Current ForceConnect State : " + forceConnect);
    }

    @Override
    public String getHelp() {
        StringBuilder help = new StringBuilder();
        help.append("---OVSDB CLI---\n");
        help.append("\t ovsconnect <ConnectionName> <ip-address>                        - Connect to OVSDB\n");
        help.append("\t addBridge <Node> <BridgeName>                                   - Add Bridge\n");
        help.append("\t getBridgeDomains <Node>                                         - Get Bridges\n");
        help.append("\t deleteBridgeDomain <Node> <BridgeName>                          - Delete a Bridge\n");
        help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs>   - Add Port\n");
        help.append("\t deletePort <Node> <BridgeName> <PortName>                       - Delete Port\n");
        help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan>               - Add Port, Vlan\n");
        help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip>      - Add Tunnel\n");
        help.append("\t printCache <Node>                                               - Prints Table Cache");
        return help.toString();
    }
}