mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
01.05.2007 bfbbaa4e458735b6410c686a806c512f6fac7e2a
Add a new method for retrieving the "best-fit" size unit appropriate for a given number of bytes. This is intended for use in user interfaces since the value returned maybe a floating point value and subject to small errors. For LDAP encoding/decoding we still have the original getBestFitUnit() method but it has been renamed to getBestFitUnitExact(). Both methods are class methods.
4 files modified
271 ■■■■ changed files
opends/src/server/org/opends/server/admin/SizePropertyDefinition.java 3 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/SizeUnit.java 199 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java 14 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java 55 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
@@ -312,9 +312,10 @@
        return UNLIMITED;
      }
    }
    // Encode the size value using the best-fit unit.
    StringBuilder builder = new StringBuilder();
    SizeUnit unit = SizeUnit.BYTES.getBestFitUnit(value);
    SizeUnit unit = SizeUnit.getBestFitUnitExact(value);
    // Cast to a long to remove fractional part (which should not be there
    // anyway as the best-fit unit should result in an exact conversion).
opends/src/server/org/opends/server/admin/SizeUnit.java
@@ -46,24 +46,9 @@
  BYTES(1L, "b", "bytes"),
  /**
   * A kilo-byte unit.
   * A gibi-byte unit.
   */
  KILO_BYTES(1000L, "kb", "kilobytes"),
  /**
   * A kibi-byte unit.
   */
  KIBI_BYTES(1024L, "kib", "kibibytes"),
  /**
   * A mega-byte unit.
   */
  MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
  /**
   * A mebi-byte unit.
   */
  MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
  GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
  /**
   * A giga-byte unit.
@@ -71,19 +56,34 @@
  GIGA_BYTES((long) 1000 * 1000 * 1000, "gb", "gigabytes"),
  /**
   * A gibi-byte unit.
   * A kibi-byte unit.
   */
  GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
  KIBI_BYTES(1024L, "kib", "kibibytes"),
  /**
   * A tera-byte unit.
   * A kilo-byte unit.
   */
  TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes"),
  KILO_BYTES(1000L, "kb", "kilobytes"),
  /**
   * A mebi-byte unit.
   */
  MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
  /**
   * A mega-byte unit.
   */
  MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
  /**
   * A tebi-byte unit.
   */
  TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes");
  TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes"),
  /**
   * A tera-byte unit.
   */
  TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes");
  // A lookup table for resolving a unit from its name.
  private static final Map<String, SizeUnit> nameToUnit;
@@ -99,15 +99,120 @@
  /**
   * Gets the best-fit unit for the specified number of bytes. The
   * returned unit will be able to represent the number of bytes using
   * a decimal number comprising of an integer part which is greater
   * than zero. Bigger units are chosen in preference to smaller units
   * and binary units are only returned if they are an exact fit. If
   * the number of bytes is zero then the {@link #BYTES} unit is
   * always returned. For example:
   *
   * <pre>
   * getBestFitUnit(0)       // BYTES
   * getBestFitUnit(999)     // BYTES
   * getBestFitUnit(1000)    // KILO_BYTES
   * getBestFitUnit(1024)    // KIBI_BYTES
   * getBestFitUnit(1025)    // KILO_BYTES
   * getBestFitUnit(999999)  // KILO_BYTES
   * getBestFitUnit(1000000) // MEGA_BYTES
   * </pre>
   *
   * @param bytes
   *          The number of bytes.
   * @return Returns the best fit unit.
   * @throws IllegalArgumentException
   *           If <code>bytes</code> is negative.
   * @see #getBestFitUnitExact(long)
   */
  public static SizeUnit getBestFitUnit(long bytes)
      throws IllegalArgumentException {
    if (bytes < 0) {
      throw new IllegalArgumentException("negative number of bytes: " + bytes);
    } else if (bytes == 0) {
      // Always use bytes for zero values.
      return BYTES;
    } else {
      // Determine best fit: prefer non-binary units unless binary
      // fits exactly.
      SizeUnit[] nonBinary = new SizeUnit[] { TERA_BYTES, GIGA_BYTES,
          MEGA_BYTES, KILO_BYTES };
      SizeUnit[] binary = new SizeUnit[] { TEBI_BYTES, GIBI_BYTES, MEBI_BYTES,
          KIBI_BYTES };
      for (int i = 0; i < nonBinary.length; i++) {
        if ((bytes % binary[i].getSize()) == 0) {
          return binary[i];
        } else if ((bytes / nonBinary[i].getSize()) > 0) {
          return nonBinary[i];
        }
      }
      return BYTES;
    }
  }
  /**
   * Gets the best-fit unit for the specified number of bytes which
   * can represent the provided value using an integral value. Bigger
   * units are chosen in preference to smaller units. If the number of
   * bytes is zero then the {@link #BYTES} unit is always returned.
   * For example:
   *
   * <pre>
   * getBestFitUnitExact(0)       // BYTES
   * getBestFitUnitExact(999)     // BYTES
   * getBestFitUnitExact(1000)    // KILO_BYTES
   * getBestFitUnitExact(1024)    // KIBI_BYTES
   * getBestFitUnitExact(1025)    // BYTES
   * getBestFitUnitExact(999999)  // BYTES
   * getBestFitUnitExact(1000000) // MEGA_BYTES
   * </pre>
   *
   * @param bytes
   *          The number of bytes.
   * @return Returns the best fit unit can represent the provided
   *         value using an integral value.
   * @throws IllegalArgumentException
   *           If <code>bytes</code> is negative.
   * @see #getBestFitUnit(long)
   */
  public static SizeUnit getBestFitUnitExact(long bytes)
      throws IllegalArgumentException {
    if (bytes < 0) {
      throw new IllegalArgumentException("negative number of bytes: " + bytes);
    } else if (bytes == 0) {
      // Always use bytes for zero values.
      return BYTES;
    } else {
      // Determine best fit.
      SizeUnit[] units = new SizeUnit[] { TEBI_BYTES, TERA_BYTES, GIBI_BYTES,
          GIGA_BYTES, MEBI_BYTES, MEGA_BYTES, KIBI_BYTES, KILO_BYTES };
      for (SizeUnit unit : units) {
        if ((bytes % unit.getSize()) == 0) {
          return unit;
        }
      }
      return BYTES;
    }
  }
  /**
   * Get the unit corresponding to the provided unit name.
   *
   * @param s
   *          The name of the unit. Can be the abbreviated or long name and can
   *          contain white space and mixed case characters.
   *          The name of the unit. Can be the abbreviated or long
   *          name and can contain white space and mixed case
   *          characters.
   * @return Returns the unit corresponding to the provided unit name.
   * @throws IllegalArgumentException
   *           If the provided name did not correspond to a known memory size
   *           unit.
   *           If the provided name did not correspond to a known
   *           memory size unit.
   */
  public static SizeUnit getUnit(String s) throws IllegalArgumentException {
    SizeUnit unit = nameToUnit.get(s.trim().toLowerCase());
@@ -188,14 +293,14 @@
    return unit.toBytes(d);
  }
  // The size of the unit in bytes.
  private final long sz;
  // The long name of the unit.
  private final String longName;
  // The abbreviation of the unit.
  private final String shortName;
  // The long name of the unit.
  private final String longName;
  // The size of the unit in bytes.
  private final long sz;
@@ -222,37 +327,6 @@
  /**
   * Get the best-fit unit for the specified amount in this unit. The returned
   * unit will be able to represent the amount using an integral value (i.e. no
   * fractional part).For example, if this unit is kilo-bytes and the amount
   * 2000 is provided, then the best fit unit is mega-bytes: 2mb. Similarly, if
   * the amount is 0.5, then the best fit unit will by bytes: 500b.
   * <p>
   * Only non-binary units are considered (i.e. kilo, mega, etc).
   *
   * @param amount
   *          The amount of this unit.
   * @return Returns the best-fit unit for the specified amount in this unit.
   */
  public SizeUnit getBestFitUnit(double amount) {
    long bytes = toBytes(amount);
    if (bytes == 0) {
      return this;
    } else if (bytes > 0) {
      // use array of SizeUnits; EnumSet iterates in natural order
      for (SizeUnit unit : new SizeUnit[]{TERA_BYTES, GIGA_BYTES, MEGA_BYTES,
              KILO_BYTES }) {
        if ((bytes % unit.sz) == 0) {
          return unit;
        }
      }
    }
    return BYTES;
  }
  /**
   * Get the long name of this unit.
   *
   * @return Returns the long name of this unit.
@@ -301,7 +375,8 @@
  /**
   * {@inheritDoc}
   * <p>
   * This implementation returns the abbreviated name of this size unit.
   * This implementation returns the abbreviated name of this size
   * unit.
   */
  @Override
  public String toString() {
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
@@ -255,10 +255,11 @@
            {1000L, "1kb"},
            {1001L, "1001b"},
            {1023L, "1023b"},
            {1024L, "1024b"},
            {1024L, "1kib"},
            {1025L, "1025b"},
            {1000L * 1000L, "1mb"},
            {1000L * 1000L * 1000L, "1gb"},
            {1024L * 1024L * 1024L, "1gib"},
            {1000L * 1000L * 1000L * 1000L, "1tb"}
    };
@@ -313,14 +314,20 @@
    spd.toString();
  }
  /**
   * Test comparator method.
   */
  @Test
  public void testCompare() {
    SizePropertyDefinition.Builder builder = createTestBuilder();
    builder.setAllowUnlimited(true);
    SizePropertyDefinition spd = buildTestDefinition(builder);
    spd.compare(1L, 2L);
    assertEquals(spd.compare(1L, 2L), -1);
  }
  /**
   * Tests default behavior.
   */
  @Test
  public void testSetDefaultBehaviorProvider() {
    SizePropertyDefinition.Builder builder = createTestBuilder();
@@ -332,6 +339,9 @@
    });
  }
  /**
   * Tests option setting.
   */
  @Test
  public void testSetOption() {
    SizePropertyDefinition.Builder builder = createTestBuilder();
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
@@ -214,28 +214,57 @@
   *
   * @return data
   */
  @DataProvider(name = "bestFitData")
  public Object[][] createBestFitData() {
  @DataProvider(name = "bestFitUnitExactData")
  public Object[][] createBestFitExactData() {
    return new Object[][]{
            { SizeUnit.KILO_BYTES, Double.MIN_VALUE, SizeUnit.KILO_BYTES },
            { SizeUnit.KILO_BYTES, 0D, SizeUnit.KILO_BYTES },
            { SizeUnit.KILO_BYTES, 0.5D, SizeUnit.BYTES },
            { SizeUnit.KILO_BYTES, 1999D, SizeUnit.KILO_BYTES },
            { SizeUnit.KILO_BYTES, 2000D, SizeUnit.MEGA_BYTES },
            { SizeUnit.KILO_BYTES, 2001D, SizeUnit.KILO_BYTES },
            // { SizeUnit.KILO_BYTES, Double.MAX_VALUE, SizeUnit.KILO_BYTES }  // fails
            { 0, SizeUnit.BYTES },
            { 999, SizeUnit.BYTES },
            { 1000, SizeUnit.KILO_BYTES },
            { 1024, SizeUnit.KIBI_BYTES },
            { 1025, SizeUnit.BYTES },
            { 999999, SizeUnit.BYTES },
            { 1000000, SizeUnit.MEGA_BYTES },
            { 1000001, SizeUnit.BYTES }
    };
  }
  /**
   * Test best fit
   * @param unit to use
   * @param value for which best fit sought
   * @param expectedUnit for comparison
   */
  @Test(dataProvider = "bestFitData")
  public void testGetBestFitUnit(SizeUnit unit, double value, SizeUnit expectedUnit) {
    assertEquals(unit.getBestFitUnit(value), expectedUnit);
  @Test(dataProvider = "bestFitUnitExactData")
  public void testGetBestFitUnitExact(long value, SizeUnit expectedUnit) {
    assertEquals(SizeUnit.getBestFitUnitExact(value), expectedUnit);
  }
  /**
   * Creates data for testing fromBytes
   *
   * @return data
   */
  @DataProvider(name = "bestFitUnitData")
  public Object[][] createBestFitData() {
    return new Object[][]{
            { 0, SizeUnit.BYTES },
            { 999, SizeUnit.BYTES },
            { 1000, SizeUnit.KILO_BYTES },
            { 1024, SizeUnit.KIBI_BYTES },
            { 1025, SizeUnit.KILO_BYTES },
            { 999999, SizeUnit.KILO_BYTES },
            { 1000000, SizeUnit.MEGA_BYTES },
            { 1000001, SizeUnit.MEGA_BYTES }
    };
  }
  /**
   * Test best fit
   * @param value for which best fit sought
   * @param expectedUnit for comparison
   */
  @Test(dataProvider = "bestFitUnitData")
  public void testGetBestFitUnit(long value, SizeUnit expectedUnit) {
    assertEquals(SizeUnit.getBestFitUnit(value), expectedUnit);
  }
  /**