Refactored bridge config to take bridge description

OVSDB provides lots of bridge configuration options but the exisisting
bridge config implementation only allows some of them by overloading
addBridge method. Also some of the bridge properties were set static
and unable to configure. This patch fixes these limitations.

- Added some bridge config options to the bridge description
- Deprecated multiple overloaded addBridge methods
- Some code clean up

Change-Id: Ibc828177b210bd4b215aea0b63cc359776c13e03
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java
index 1461db3..3b47079 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java
@@ -31,31 +31,45 @@
     /**
      * Add a bridge.
      *
+     * @deprecated version 1.7.0 - Hummingbird
      * @param bridgeName bridge name
      */
+    @Deprecated
     void addBridge(BridgeName bridgeName);
 
     /**
      * Adds a bridge with given bridge name, dpid and exPortName.
      *
+     * @deprecated version 1.7.0 - Hummingbird
      * @param bridgeName bridge name
      * @param dpid dpid
      * @param exPortName external port name
      */
+    @Deprecated
     void addBridge(BridgeName bridgeName, String dpid, String exPortName);
 
     /**
      * Adds a bridge with given bridge name and dpid, and sets the controller
      * of the bridge with given controllers.
      *
+     * @deprecated version 1.7.0 - Hummingbird
      * @param bridgeName bridge name
      * @param dpid dpid
      * @param controllers list of controller
      * @return true if succeeds, fail otherwise
      */
+    @Deprecated
     boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers);
 
     /**
+     * Adds a bridge with a given description.
+     *
+     * @param bridgeDescription bridge description
+     * @return true if succeeds, or false
+     */
+    boolean addBridge(BridgeDescription bridgeDescription);
+
+    /**
      * Remove a bridge.
      *
      * @param bridgeName bridge name
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
index e945ade..a8c0832 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java
@@ -18,29 +18,140 @@
 import org.onosproject.net.Description;
 import org.onosproject.net.DeviceId;
 
+import java.util.List;
+import java.util.Optional;
+
 /**
- * The abstraction of bridge in OVSDB protocol.
+ * The abstraction of a bridge. Bridge represents an Ethernet switch with no or
+ * multiple OpenFlow controllers. Only OVSDB device provides bridge config behavior
+ * now and the bridge description is based on OVSDB schema.
  */
 public interface BridgeDescription extends Description {
 
+    enum FailMode {
+        /**
+         * The bridge will not set up flows on its own when the controller
+         * connection fails or no controllers are defined.
+         */
+        SECURE,
+        /**
+         * The bridge will take over responsibility of setting up flows.
+         */
+        STANDALONE
+    }
+
     /**
      * Returns bridge name.
      *
      * @return bridge name
      */
-    BridgeName bridgeName();
+    String name();
 
     /**
-     * Returns controller identifier that this bridge belongs to.
+     * Returns OpenFlow controllers of the bridge.
+     * If it's empty, then no OpenFlow controllers are used for the bridge.
      *
-     * @return controller identifier
+     * @return set of controllers
      */
-    DeviceId cotrollerDeviceId();
+    List<ControllerInfo> controllers();
 
     /**
-     * Returns bridge identifier .
+     * Returns whether to use local controller as an OpenFlow controller of the
+     * bridge if no controllers are specified.
      *
-     * @return bridge identifier
+     * @return true to set local controller, false otherwise
      */
-    DeviceId deviceId();
+    boolean enableLocalController();
+
+    /**
+     * Returns fail mode of the bridge.
+     * If it's not set, the default setting of the bridge is used.
+     *
+     * @return fail mode
+     */
+    Optional<FailMode> failMode();
+
+    /**
+     * Returns OpenFlow datapath ID of the bridge. Valid only if OpenFlow controller
+     * is configured for the bridge.
+     *
+     * @return datapath id
+     */
+    Optional<String> datapathId();
+
+    /**
+     * Returns OpenFlow device ID. Valid only if OpenFlow controller is configured
+     * for the bridge.
+     *
+     * @return device id
+     */
+    Optional<DeviceId> deviceId();
+
+    /**
+     * Returns in band control is enabled or not. If set to true, disable in-band
+     * control on the bridge regardless of controller and manager settings.
+     * If it's not set, the default setting of the bridge is used.
+     *
+     * @return true if in-band is disabled, false if in-band is enabled
+     */
+    Optional<Boolean> disableInBand();
+
+    /**
+     * Builder of bridge description entities.
+     */
+    interface Builder {
+
+        /**
+         * Returns bridge description builder with a given name.
+         *
+         * @param name bridge name
+         * @return bridge description builder
+         */
+        Builder name(String name);
+
+        /**
+         * Returns bridge description builder with given controllers.
+         *
+         * @param controllers set of controllers
+         * @return bridge description builder
+         */
+        Builder controllers(List<ControllerInfo> controllers);
+
+        /**
+         * Returns bridge description builder with local controller enabled.
+         *
+         * @return bridge description builder
+         */
+        Builder enableLocalController();
+
+        /**
+         * Returns bridge description builder with a given fail mode.
+         *
+         * @param failMode fail mode
+         * @return bridge description builder
+         */
+        Builder failMode(FailMode failMode);
+
+        /**
+         * Returns bridge description builder with a given datapath ID.
+         *
+         * @param datapathId datapath id
+         * @return bridge description builder
+         */
+        Builder datapathId(String datapathId);
+
+        /**
+         * Returns bridge description builder with in-band control disabled.
+         *
+         * @return bridge description builder
+         */
+        Builder disableInBand();
+
+        /**
+         * Builds an immutable bridge description.
+         *
+         * @return bridge description
+         */
+        BridgeDescription build();
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java b/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
index 6bd73a8..f35b646 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java
@@ -15,73 +15,158 @@
  */
 package org.onosproject.net.behaviour;
 
-import java.util.Objects;
-
-import org.onosproject.net.AbstractDescription;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.SparseAnnotations;
 
-import com.google.common.base.MoreObjects;
+import java.util.List;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * The default implementation of bridge.
  */
-public final class DefaultBridgeDescription extends AbstractDescription
-        implements BridgeDescription {
+public final class DefaultBridgeDescription implements BridgeDescription {
 
-    private final BridgeName name;
-    private final DeviceId deviceId;
-    private final DeviceId controllerId;
+    private final String name;
 
-    public DefaultBridgeDescription(BridgeName name, DeviceId controllerId,
-                                    DeviceId deviceId,
-                                    SparseAnnotations... annotations) {
-        super(annotations);
-        this.name = name;
-        this.deviceId = deviceId;
-        this.controllerId = controllerId;
+    /* Optional OpenFlow configurations */
+    private final List<ControllerInfo> controllers;
+    private final boolean enableLocalController;
+    private final Optional<FailMode> failMode;
+    private final Optional<String> datapathId;
+    private final Optional<Boolean> disableInBand;
+
+    /* Adds more configurations */
+
+    private DefaultBridgeDescription(String name,
+                                     List<ControllerInfo> controllers,
+                                     boolean enableLocalController,
+                                     Optional<FailMode> failMode,
+                                     Optional<String> datapathId,
+                                     Optional<Boolean> disableInBand) {
+        this.name = checkNotNull(name);
+        this.controllers = controllers;
+        this.enableLocalController = enableLocalController;
+        this.failMode = failMode;
+        this.datapathId = datapathId;
+        this.disableInBand = disableInBand;
     }
 
     @Override
-    public BridgeName bridgeName() {
+    public SparseAnnotations annotations() {
+        return null;
+    }
+
+    @Override
+    public String name() {
         return name;
     }
 
     @Override
-    public DeviceId deviceId() {
-        return deviceId;
+    public List<ControllerInfo> controllers() {
+        return controllers;
     }
 
     @Override
-    public DeviceId cotrollerDeviceId() {
-        return controllerId;
+    public boolean enableLocalController() {
+        return enableLocalController;
     }
 
     @Override
-    public int hashCode() {
-        return Objects.hash(name, deviceId, controllerId);
+    public Optional<FailMode> failMode() {
+        return failMode;
     }
 
     @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
+    public Optional<String> datapathId() {
+        return datapathId;
+    }
+
+    @Override
+    public Optional<DeviceId> deviceId() {
+        if (datapathId.isPresent()) {
+            return Optional.of(DeviceId.deviceId("of:" + datapathId.get()));
+        } else {
+            return Optional.empty();
         }
-        if (obj instanceof DefaultBridgeDescription) {
-            final DefaultBridgeDescription that = (DefaultBridgeDescription) obj;
-            return this.getClass() == that.getClass()
-                    && Objects.equals(this.name, that.name)
-                    && Objects.equals(this.deviceId, that.deviceId)
-                    && Objects.equals(this.controllerId, that.controllerId);
-        }
-        return false;
     }
 
     @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass()).add("name", name)
-                .add("deviceId", deviceId).add("controllerId", controllerId)
-                .toString();
+    public Optional<Boolean> disableInBand() {
+        return disableInBand;
     }
 
+    /**
+     * Creates and returns a new builder instance.
+     *
+     * @return new builder
+     */
+    public static BridgeDescription.Builder builder() {
+        return new Builder();
+    }
+
+    public static final class Builder implements BridgeDescription.Builder {
+
+        private String name;
+        private List<ControllerInfo> controllers = Lists.newArrayList();
+        private boolean enableLocalController = false;
+        private Optional<FailMode> failMode = Optional.empty();
+        private Optional<String> datapathId = Optional.empty();
+        private Optional<Boolean> disableInBand = Optional.empty();
+
+        private Builder() {
+        }
+
+        @Override
+        public BridgeDescription build() {
+            return new DefaultBridgeDescription(name, controllers,
+                                                enableLocalController,
+                                                failMode,
+                                                datapathId,
+                                                disableInBand);
+        }
+
+        @Override
+        public Builder name(String name) {
+            checkArgument(!Strings.isNullOrEmpty(name));
+            this.name = name;
+            return this;
+        }
+
+        @Override
+        public Builder controllers(List<ControllerInfo> controllers) {
+            if (controllers != null) {
+                this.controllers = Lists.newArrayList(controllers);
+            }
+            return this;
+        }
+
+        @Override
+        public Builder enableLocalController() {
+            this.enableLocalController = true;
+            return this;
+        }
+
+        @Override
+        public Builder failMode(FailMode failMode) {
+            this.failMode = Optional.ofNullable(failMode);
+            return this;
+        }
+
+        @Override
+        public Builder datapathId(String datapathId) {
+            this.datapathId = Optional.ofNullable(datapathId);
+            return this;
+        }
+
+        @Override
+        public Builder disableInBand() {
+            this.disableInBand = Optional.of(Boolean.TRUE);
+            return this;
+        }
+    }
 }