Define sub-types of Bandwidth to reduce round-off error

Two sub-types are defined
- LongBandwidth
- DoubleBandwidth
LongBandwidth can reduce round-off error cause by floating point arithmetics.
These classes are not exposed outside the package and only instantiated
through static factory methods.

Change-Id: Ice5d8ff1397c9dd9c8c1fff46af256fff08fa616
diff --git a/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
index 713b4b5..e2753b2 100644
--- a/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
@@ -371,7 +371,13 @@
 
         // Check for a bandwidth specification
         if (!isNullOrEmpty(bandwidthString)) {
-            final Bandwidth bandwidth = Bandwidth.bps(Double.parseDouble(bandwidthString));
+            Bandwidth bandwidth;
+            try {
+                bandwidth = Bandwidth.bps(Long.parseLong(bandwidthString));
+            // when the string can't be parsed as long, then try to parse as double
+            } catch (NumberFormatException e) {
+                bandwidth = Bandwidth.bps(Double.parseDouble(bandwidthString));
+            }
             constraints.add(new BandwidthConstraint(bandwidth));
         }
 
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 7223d57..16a2a99 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -267,6 +267,8 @@
             .register(VlanId.class)
             .register(Frequency.class)
             .register(Bandwidth.class)
+            .register(Bandwidth.bps(1L).getClass())
+            .register(Bandwidth.bps(1.0).getClass())
             .build();
 
     /**
@@ -283,7 +285,7 @@
             .register(BASIC)
             .nextId(KryoNamespace.INITIAL_ID + 30)
             .register(MISC)
-            .nextId(KryoNamespace.INITIAL_ID + 30 + 10)
+            .nextId(KryoNamespace.INITIAL_ID + 30 + 20)
             .register(
                     Instructions.MeterInstruction.class,
                     MeterId.class,
diff --git a/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java b/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java
index aca0acc..9ee9cd9 100644
--- a/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java
+++ b/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java
@@ -397,6 +397,7 @@
 
     @Test
     public void testBandwidth() {
+        testSerializedEquals(Bandwidth.mbps(1000));
         testSerializedEquals(Bandwidth.mbps(1000.0));
     }
 
diff --git a/utils/misc/src/main/java/org/onlab/util/Bandwidth.java b/utils/misc/src/main/java/org/onlab/util/Bandwidth.java
index 6080656..ab07b71 100644
--- a/utils/misc/src/main/java/org/onlab/util/Bandwidth.java
+++ b/utils/misc/src/main/java/org/onlab/util/Bandwidth.java
@@ -17,28 +17,21 @@
 
 import com.google.common.collect.ComparisonChain;
 
-import java.util.Objects;
-
 /**
  * Representation of bandwidth.
  * Use the static factory method corresponding to the unit (like Kbps) you desire on instantiation.
  */
-public final class Bandwidth implements RichComparable<Bandwidth> {
-
-    private final double bps;
+public interface Bandwidth extends RichComparable<Bandwidth> {
 
     /**
      * Creates a new instance with given bandwidth.
      *
-     * @param bps bandwidth value to be assigned
+     * @param v         bandwidth value
+     * @param unit      {@link DataRateUnit} of {@code v}
+     * @return {@link Bandwidth} instance with given bandwidth
      */
-    private Bandwidth(double bps) {
-        this.bps = bps;
-    }
-
-    // Constructor for serialization
-    private Bandwidth() {
-        this.bps = 0;
+    static Bandwidth of(long v, DataRateUnit unit) {
+        return new LongBandwidth(unit.toBitsPerSecond(v));
     }
 
     /**
@@ -48,8 +41,8 @@
      * @param unit      {@link DataRateUnit} of {@code v}
      * @return {@link Bandwidth} instance with given bandwidth
      */
-    public static Bandwidth of(double v, DataRateUnit unit) {
-        return new Bandwidth(unit.toBitsPerSecond(v));
+    static Bandwidth of(double v, DataRateUnit unit) {
+        return new DoubleBandwidth(unit.toBitsPerSecond(v));
     }
 
     /**
@@ -58,8 +51,18 @@
      * @param bps bandwidth value to be assigned
      * @return {@link Bandwidth} instance with given bandwidth
      */
-    public static Bandwidth bps(double bps) {
-        return new Bandwidth(bps);
+    static Bandwidth bps(long bps) {
+        return new LongBandwidth(bps);
+    }
+
+    /**
+     * Creates a new instance with given bandwidth in bps.
+     *
+     * @param bps bandwidth value to be assigned
+     * @return {@link Bandwidth} instance with given bandwidth
+     */
+    static Bandwidth bps(double bps) {
+        return new DoubleBandwidth(bps);
     }
 
     /**
@@ -68,7 +71,17 @@
      * @param kbps bandwidth value to be assigned
      * @return {@link Bandwidth} instance with given bandwidth
      */
-    public static Bandwidth kbps(double kbps) {
+    static Bandwidth kbps(long kbps) {
+        return bps(kbps * 1_000L);
+    }
+
+    /**
+     * Creates a new instance with given bandwidth in Kbps.
+     *
+     * @param kbps bandwidth value to be assigned
+     * @return {@link Bandwidth} instance with given bandwidth
+     */
+    static Bandwidth kbps(double kbps) {
         return bps(kbps * 1_000L);
     }
 
@@ -78,7 +91,17 @@
      * @param mbps bandwidth value to be assigned
      * @return {@link Bandwidth} instance with given bandwidth
      */
-    public static Bandwidth mbps(double mbps) {
+    static Bandwidth mbps(long mbps) {
+        return bps(mbps * 1_000_000L);
+    }
+
+    /**
+     * Creates a new instance with given bandwidth in Mbps.
+     *
+     * @param mbps bandwidth value to be assigned
+     * @return {@link Bandwidth} instance with given bandwidth
+     */
+    static Bandwidth mbps(double mbps) {
         return bps(mbps * 1_000_000L);
     }
 
@@ -88,7 +111,17 @@
      * @param gbps bandwidth value to be assigned
      * @return {@link Bandwidth} instance with given bandwidth
      */
-    public static Bandwidth gbps(double gbps) {
+    static Bandwidth gbps(long gbps) {
+        return bps(gbps * 1_000_000_000L);
+    }
+
+    /**
+     * Creates a new instance with given bandwidth in Gbps.
+     *
+     * @param gbps bandwidth value to be assigned
+     * @return {@link Bandwidth} instance with given bandwidth
+     */
+    static Bandwidth gbps(double gbps) {
         return bps(gbps * 1_000_000_000L);
     }
 
@@ -97,9 +130,7 @@
      *
      * @return bandwidth in bps.
      */
-    public double bps() {
-        return bps;
-    }
+    double bps();
 
     /**
      * Returns a Bandwidth whose value is (this + value).
@@ -107,8 +138,8 @@
      * @param value value to be added to this Frequency
      * @return this + value
      */
-    public Bandwidth add(Bandwidth value) {
-        return bps(this.bps + value.bps);
+    default Bandwidth add(Bandwidth value) {
+        return bps(this.bps() + value.bps());
     }
 
     /**
@@ -117,33 +148,14 @@
      * @param value value to be added to this Frequency
      * @return this - value
      */
-    public Bandwidth subtract(Bandwidth value) {
-        return bps(this.bps - value.bps);
+    default Bandwidth subtract(Bandwidth value) {
+        return bps(this.bps() - value.bps());
     }
 
     @Override
-    public int compareTo(Bandwidth other) {
+    default int compareTo(Bandwidth other) {
         return ComparisonChain.start()
-                .compare(this.bps, other.bps)
+                .compare(this.bps(), other.bps())
                 .result();
     }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof Bandwidth) {
-            Bandwidth that = (Bandwidth) obj;
-            return Objects.equals(this.bps, that.bps);
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Long.hashCode(Double.doubleToLongBits(bps));
-    }
-
-    @Override
-    public String toString() {
-        return String.valueOf(this.bps);
-    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/util/DoubleBandwidth.java b/utils/misc/src/main/java/org/onlab/util/DoubleBandwidth.java
new file mode 100644
index 0000000..69f2529
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/DoubleBandwidth.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.util;
+
+import java.util.Objects;
+
+/**
+ * Representation of bandwidth.
+ * Use the static factory method corresponding to the unit (like Kbps) you desire on instantiation.
+ */
+final class DoubleBandwidth implements Bandwidth {
+
+    private final double bps;
+
+    /**
+     * Creates a new instance with given bandwidth.
+     *
+     * @param bps bandwidth value to be assigned
+     */
+    DoubleBandwidth(double bps) {
+        this.bps = bps;
+    }
+
+    // Constructor for serialization
+    private DoubleBandwidth() {
+        this.bps = 0;
+    }
+    /**
+     * Returns bandwidth in bps.
+     *
+     * @return bandwidth in bps.
+     */
+    public double bps() {
+        return bps;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof DoubleBandwidth)) {
+            return false;
+        }
+
+        DoubleBandwidth that = (DoubleBandwidth) obj;
+        return Objects.equals(this.bps, that.bps);
+    }
+
+    @Override
+    public int hashCode() {
+        return Long.hashCode(Double.doubleToLongBits(bps));
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(this.bps);
+    }
+}
diff --git a/utils/misc/src/main/java/org/onlab/util/LongBandwidth.java b/utils/misc/src/main/java/org/onlab/util/LongBandwidth.java
new file mode 100644
index 0000000..d45f715
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/LongBandwidth.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.util;
+
+import com.google.common.collect.ComparisonChain;
+
+/**
+ * Representation of bandwidth.
+ * Use the static factory method corresponding to the unit (like Kbps) you desire on instantiation.
+ */
+final class LongBandwidth implements Bandwidth {
+
+    private final long bps;
+
+    /**
+     * Creates a new instance with given bandwidth.
+     *
+     * @param bps bandwidth value to be assigned
+     */
+    LongBandwidth(long bps) {
+        this.bps = bps;
+    }
+
+    // Constructor for serialization
+    private LongBandwidth() {
+        this.bps = 0;
+    }
+    /**
+     * Returns bandwidth in bps.
+     *
+     * @return bandwidth in bps.
+     */
+    public double bps() {
+        return bps;
+    }
+
+    /**
+     * Returns a Bandwidth whose value is (this + value).
+     *
+     * @param value value to be added to this Frequency
+     * @return this + value
+     */
+    public Bandwidth add(Bandwidth value) {
+        if (value instanceof LongBandwidth) {
+            return Bandwidth.bps(this.bps + ((LongBandwidth) value).bps);
+        }
+        return Bandwidth.bps(this.bps + value.bps());
+    }
+
+    /**
+     * Returns a Bandwidth whose value is (this - value).
+     *
+     * @param value value to be added to this Frequency
+     * @return this - value
+     */
+    public Bandwidth subtract(Bandwidth value) {
+        if (value instanceof LongBandwidth) {
+            return Bandwidth.bps(this.bps - ((LongBandwidth) value).bps);
+        }
+        return Bandwidth.bps(this.bps - value.bps());
+    }
+
+    @Override
+    public int compareTo(Bandwidth other) {
+        if (other instanceof LongBandwidth) {
+            return ComparisonChain.start()
+                    .compare(this.bps, ((LongBandwidth) other).bps)
+                    .result();
+        }
+        return ComparisonChain.start()
+                .compare(this.bps, other.bps())
+                .result();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Bandwidth) {
+            return this.compareTo((Bandwidth) obj) == 0;
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Long.hashCode(bps);
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(this.bps);
+    }
+}