From a295a5d43c99eb1e1d54fbbfce87a37bf7762cbb Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 21 Nov 2017 15:24:42 -0500 Subject: [PATCH 1/7] Add Quantity type and tests --- .../client/custom/BaseExponent.java | 56 ++++++++ .../io/kubernetes/client/custom/Pair.java | 20 +++ .../io/kubernetes/client/custom/Quantity.java | 71 ++++++++++ .../custom/QuantityFormatException.java | 7 + .../client/custom/QuantityFormatter.java | 90 +++++++++++++ .../client/custom/SuffixFormatter.java | 107 +++++++++++++++ .../client/custom/QuantityFormatterTest.java | 126 ++++++++++++++++++ .../client/custom/SuffixFormatterTest.java | 115 ++++++++++++++++ 8 files changed, 592 insertions(+) create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatException.java create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java create mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/SuffixFormatter.java create mode 100644 kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java create mode 100644 kubernetes/src/test/java/io/kubernetes/client/custom/SuffixFormatterTest.java diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java new file mode 100644 index 0000000000..44f850cf28 --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java @@ -0,0 +1,56 @@ +package io.kubernetes.client.custom; + +public class BaseExponent { + + private final int base; + + private final int exponent; + + private final Quantity.Format format; + public BaseExponent(int base, int exponent, Quantity.Format format) { + this.base = base; + this.exponent = exponent; + this.format = format; + } + + public int getBase() { + return base; + } + + public int getExponent() { + return exponent; + } + + public Quantity.Format getFormat() { + return format; + } + + @Override + public String toString() { + return "BaseExponent{" + + "base=" + base + + ", exponent=" + exponent + + ", format=" + format + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BaseExponent that = (BaseExponent) o; + + if (base != that.base) return false; + if (exponent != that.exponent) return false; + return format == that.format; + } + + @Override + public int hashCode() { + int result = base; + result = 31 * result + exponent; + result = 31 * result + (format != null ? format.hashCode() : 0); + return result; + } +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java b/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java new file mode 100644 index 0000000000..8925587e7d --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java @@ -0,0 +1,20 @@ +package io.kubernetes.client.custom; + +public class Pair { + + private final L left; + private final R right; + + public Pair(final L left, final R right) { + this.left = left; + this.right = right; + } + + public L getLeft() { + return left; + } + + public R getRight() { + return right; + } +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java new file mode 100644 index 0000000000..82e696051e --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java @@ -0,0 +1,71 @@ +package io.kubernetes.client.custom; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.math.BigDecimal; + +@JsonAdapter(Quantity.QuantityAdapter.class) +public class Quantity { + + private final BigDecimal number; + private Format format; + + public enum Format { + DECIMAL_EXPONENT(10), DECIMAL_SI(10), BINARY_SI(2); + + private int base; + + Format(final int base) { + this.base = base; + } + + public int getBase() { + return base; + } + } + + public Quantity(final BigDecimal number, final Format format) { + this.number = number; + this.format = format; + } + + public BigDecimal getBigDecimal() { + return number; + } + + public Format getFormat() { + return format; + } + + public static Quantity fromString(final String value) { + return new QuantityFormatter().parse(value); + } + + public String toSuffixedString() { + return new QuantityFormatter().format(this); + } + + @Override + public String toString() { + return "Quantity{" + + "number=" + number + + ", format=" + format + + '}'; + } + + public class QuantityAdapter extends TypeAdapter { + @Override + public void write(JsonWriter jsonWriter, Quantity quantity) throws IOException { + jsonWriter.value(quantity.toSuffixedString()); + } + + @Override + public Quantity read(JsonReader jsonReader) throws IOException { + return Quantity.fromString(jsonReader.nextString()); + } + } +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatException.java b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatException.java new file mode 100644 index 0000000000..909bd987c7 --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatException.java @@ -0,0 +1,7 @@ +package io.kubernetes.client.custom; + +public class QuantityFormatException extends RuntimeException { + public QuantityFormatException(String s) { + super(s); + } +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java new file mode 100644 index 0000000000..7f32a25a4a --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java @@ -0,0 +1,90 @@ +package io.kubernetes.client.custom; + +import java.math.BigDecimal; +import java.math.MathContext; + +public class QuantityFormatter { + + private static final String PARTS_RE = "[eEinumkKMGTP]+"; + + public Quantity parse(final String value) { + if (value == null || value.isEmpty()) { + throw new QuantityFormatException(""); + } + final String[] parts = value.split(PARTS_RE); + final BigDecimal numericValue = parseNumericValue(parts[0]); + final String suffix = value.substring(parts[0].length()); + final BaseExponent baseExponent = new SuffixFormatter().parse(suffix); + final BigDecimal unitMultiplier = BigDecimal.valueOf(baseExponent.getBase()).pow(baseExponent.getExponent(), MathContext.DECIMAL64); + final BigDecimal unitlessValue = numericValue.multiply(unitMultiplier); + return new Quantity(unitlessValue, baseExponent.getFormat()); + } + + private static BigDecimal parseNumericValue(String part) { + try { + return new BigDecimal(part); + } catch (final NumberFormatException e) { + throw new QuantityFormatException("Unable to parse numeric part of quantity: " + part); + } + } + + public String format(final Quantity quantity) { + switch (quantity.getFormat()) { + case DECIMAL_SI: + case DECIMAL_EXPONENT: + return toBase10String(quantity); + case BINARY_SI: + if (isFractional(quantity)) { + return toBase10String(new Quantity(quantity.getBigDecimal(), Quantity.Format.DECIMAL_SI)); + } + return toBase1024String(quantity); + default: + throw new IllegalArgumentException("Can't format a " + quantity.getFormat() + " quantity"); + } + } + + private boolean isFractional(Quantity quantity) { + return quantity.getBigDecimal().scale() > 0; + } + + private String toBase1024String(final Quantity quantity) { + final BigDecimal amount = quantity.getBigDecimal(); + final long value = amount.unscaledValue().longValue(); + final int exponent = -amount.scale(); + final Pair resultAndTimes = removeFactorsForBase(value, 1024); + return resultAndTimes.getLeft() + new SuffixFormatter().format(quantity.getFormat(), exponent + resultAndTimes.getRight() * 10); + } + + private String toBase10String(final Quantity quantity) { + final BigDecimal amount = quantity.getBigDecimal(); + final long value = amount.unscaledValue().longValue(); + final int exponent = -amount.scale(); + final Pair resultAndTimes = removeFactorsForBase(value, 10); + final int postFactoringExponent = exponent + resultAndTimes.getRight(); + final Pair valueAndExponent = ensureExponentIsMultipleOf3(resultAndTimes.getLeft(), postFactoringExponent); + return valueAndExponent.getLeft() + new SuffixFormatter().format(quantity.getFormat(), valueAndExponent.getRight()); + } + + private Pair ensureExponentIsMultipleOf3(final long mantissa, final int exponent) { + final long exponentRemainder = exponent % 3; + if (exponentRemainder == 1 || exponentRemainder == -2) { + return new Pair<>(mantissa * 10, exponent - 1); + } else if (exponentRemainder == -1 || exponentRemainder == 2) { + return new Pair<>(mantissa * 100, exponent - 2); + } else { + return new Pair<>(mantissa, exponent); + } + } + + private Pair removeFactorsForBase(final long value, final int base) { + int times = 0; + long result = value; + while (result >= base && result % base == 0) { + times++; + result = result / base; + } + return new Pair<>(result, times); + } + +} + diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/SuffixFormatter.java b/kubernetes/src/main/java/io/kubernetes/client/custom/SuffixFormatter.java new file mode 100644 index 0000000000..03671cc9c1 --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/SuffixFormatter.java @@ -0,0 +1,107 @@ +package io.kubernetes.client.custom; + +import java.util.HashMap; +import java.util.Map; + +public class SuffixFormatter { + + private static final Map suffixToBinary = new HashMap() { + { + put("", new BaseExponent(2, 0, Quantity.Format.BINARY_SI)); + put("Ki", new BaseExponent(2, 10, Quantity.Format.BINARY_SI)); + put("Mi", new BaseExponent(2, 20, Quantity.Format.BINARY_SI)); + put("Gi", new BaseExponent(2, 30, Quantity.Format.BINARY_SI)); + put("Ti", new BaseExponent(2, 40, Quantity.Format.BINARY_SI)); + put("Pi", new BaseExponent(2, 50, Quantity.Format.BINARY_SI)); + put("Ei", new BaseExponent(2, 60, Quantity.Format.BINARY_SI)); + } + }; + + private static final Map suffixToDecimal = new HashMap() { + { + put("n", new BaseExponent(10, -9, Quantity.Format.DECIMAL_SI)); + put("u", new BaseExponent(10, -6, Quantity.Format.DECIMAL_SI)); + put("m", new BaseExponent(10, -3, Quantity.Format.DECIMAL_SI)); + put("", new BaseExponent(10, 0, Quantity.Format.DECIMAL_SI)); + put("k", new BaseExponent(10, 3, Quantity.Format.DECIMAL_SI)); + put("M", new BaseExponent(10, 6, Quantity.Format.DECIMAL_SI)); + put("G", new BaseExponent(10, 9, Quantity.Format.DECIMAL_SI)); + put("T", new BaseExponent(10, 12, Quantity.Format.DECIMAL_SI)); + put("P", new BaseExponent(10, 15, Quantity.Format.DECIMAL_SI)); + put("E", new BaseExponent(10, 18, Quantity.Format.DECIMAL_SI)); + } + }; + + private static final Map decimalToSuffix = new HashMap() { + { + for (Entry entry : suffixToDecimal.entrySet()) { + put(entry.getValue(), entry.getKey()); + } + } + }; + + private static final Map binaryToSuffix = new HashMap() { + { + for (Entry entry : suffixToBinary.entrySet()) { + put(entry.getValue(), entry.getKey()); + } + } + }; + + public BaseExponent parse(final String suffix) { + final BaseExponent decimalSuffix = suffixToDecimal.get(suffix); + if (decimalSuffix != null) { + return decimalSuffix; + } + + final BaseExponent binarySuffix = suffixToBinary.get(suffix); + if (binarySuffix != null) { + return binarySuffix; + } + + if (suffix.length() > 0 && (suffix.charAt(0) == 'E' || suffix.charAt(0) == 'e')) { + return extractDecimalExponent(suffix); + } + + throw new QuantityFormatException("Could not parse suffix"); + } + + private BaseExponent extractDecimalExponent(String suffix) { + try { + final int exponent = Integer.parseInt(suffix.substring(1)); + return new BaseExponent(10, exponent, Quantity.Format.DECIMAL_EXPONENT); + } catch (final NumberFormatException e) { + throw new QuantityFormatException("Can't parse decimal exponent from " + suffix.substring(1)); + } + } + + public String format(final Quantity.Format format, final int exponent) { + switch (format) { + case DECIMAL_SI: + return getDecimalSiSuffix(exponent); + case BINARY_SI: + return getBinarySiSuffix(exponent); + case DECIMAL_EXPONENT: + return exponent == 0 ? "" : "e" + exponent; + default: + throw new IllegalStateException("Can't format " + format + " with exponent " + exponent); + } + } + + private String getBinarySiSuffix(int exponent) { + final String suffix = binaryToSuffix.get(new BaseExponent(2, exponent, Quantity.Format.BINARY_SI)); + if (suffix == null) { + throw new IllegalArgumentException("No suffix for exponent" + exponent); + } + return suffix; + } + + private String getDecimalSiSuffix(int exponent) { + final String suffix = decimalToSuffix.get(new BaseExponent(10, exponent, Quantity.Format.DECIMAL_SI)); + if (suffix == null) { + throw new IllegalArgumentException("No suffix for exponent" + exponent); + } + return suffix; + } + +} diff --git a/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java new file mode 100644 index 0000000000..cd5bb8dfb4 --- /dev/null +++ b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java @@ -0,0 +1,126 @@ +package io.kubernetes.client.custom; + +import org.junit.Test; + +import java.math.BigDecimal; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class QuantityFormatterTest { + + @Test + public void testParsePlain() { + final Quantity quantity = new QuantityFormatter().parse("1"); + assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1))); + } + + @Test + public void testParseFractional() { + final Quantity quantity = new QuantityFormatter().parse("0.001"); + assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(0.001))); + } + + @Test + public void testParseFractionalUnit() { + final Quantity quantity = new QuantityFormatter().parse("0.001m"); + assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); + assertThat(quantity.getBigDecimal(), is(new BigDecimal("0.000001"))); + } + + @Test + public void testParseBinarySi() { + final Quantity quantity = new QuantityFormatter().parse("1Ki"); + assertThat(quantity.getFormat(), is(Quantity.Format.BINARY_SI)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1024))); + } + + @Test + public void testParseLargeNumeratorBinarySi() { + final Quantity quantity = new QuantityFormatter().parse("32Mi"); + assertThat(quantity.getFormat(), is(Quantity.Format.BINARY_SI)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(2).pow(20).multiply(BigDecimal.valueOf(32)))); + } + + @Test + public void testParseExponent() { + final Quantity quantity = new QuantityFormatter().parse("1e3"); + assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1000))); + } + + @Test + public void testParseNegativeExponent() { + final Quantity quantity = new QuantityFormatter().parse("1e-3"); + assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); + assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(0.001))); + } + + @Test(expected = QuantityFormatException.class) + public void testParseBad() { + new QuantityFormatter().parse("4e9e"); + } + + @Test + public void testFormatPlain() { + final String formattedString = new QuantityFormatter().format(new Quantity(new BigDecimal("100"), Quantity.Format.DECIMAL_SI)); + assertThat(formattedString, is("100")); + } + + @Test + public void testFormatDecimalSi() { + final String formattedString = new QuantityFormatter().format(new Quantity(new BigDecimal("100000"), Quantity.Format.DECIMAL_SI)); + assertThat(formattedString, is("100k")); + } + + @Test + public void testFormatFractionalDecimalSi() { + final String formattedString = new QuantityFormatter().format(new Quantity(new BigDecimal("100.001"), Quantity.Format.DECIMAL_SI)); + assertThat(formattedString, is("100001m")); + } + + @Test + public void testFormatBinarySi() { + final String formattedString = new QuantityFormatter().format(new Quantity(new BigDecimal(2).pow(20), Quantity.Format.BINARY_SI)); + assertThat(formattedString, is("1Mi")); + } + + @Test + public void testFormatLessThan1024BinarySi() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(128), Quantity.Format.BINARY_SI)); + assertThat(formattedString, is("128")); + } + + @Test + public void testFormatNon1024BinarySi() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(2056), Quantity.Format.BINARY_SI)); + assertThat(formattedString, is("2056")); + } + + @Test + public void testFormatFractionalBinarySi() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(123.123), Quantity.Format.BINARY_SI)); + assertThat(formattedString, is("123123m")); + } + + @Test + public void testFormatDecimalExponent() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(1000000), Quantity.Format.DECIMAL_EXPONENT)); + assertThat(formattedString, is("1e6")); + } + + @Test + public void testFormatEnforceExpOf3DecimalExponent() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(100000), Quantity.Format.DECIMAL_EXPONENT)); + assertThat(formattedString, is("100e3")); + } + + @Test + public void testFormatNoExpDecimalExponent() { + final String formattedString = new QuantityFormatter().format(new Quantity(BigDecimal.valueOf(12345), Quantity.Format.DECIMAL_EXPONENT)); + assertThat(formattedString, is("12345")); + } + +} diff --git a/kubernetes/src/test/java/io/kubernetes/client/custom/SuffixFormatterTest.java b/kubernetes/src/test/java/io/kubernetes/client/custom/SuffixFormatterTest.java new file mode 100644 index 0000000000..bc520650aa --- /dev/null +++ b/kubernetes/src/test/java/io/kubernetes/client/custom/SuffixFormatterTest.java @@ -0,0 +1,115 @@ +package io.kubernetes.client.custom; + +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class SuffixFormatterTest { + + @Test + public void testParseBinaryKi() { + final BaseExponent baseExponent = new SuffixFormatter().parse("Ki"); + assertThat(baseExponent.getBase(), is(2)); + assertThat(baseExponent.getExponent(), is(10)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.BINARY_SI)); + } + + @Test + public void testParseDecimalZero() { + final BaseExponent baseExponent = new SuffixFormatter().parse(""); + assertThat(baseExponent.getBase(), is(10)); + assertThat(baseExponent.getExponent(), is(0)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.DECIMAL_SI)); + } + + @Test + public void testParseDecimalK() { + final BaseExponent baseExponent = new SuffixFormatter().parse("k"); + assertThat(baseExponent.getBase(), is(10)); + assertThat(baseExponent.getExponent(), is(3)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.DECIMAL_SI)); + } + + @Test + public void testParseDecimalExponent() { + final BaseExponent baseExponent = new SuffixFormatter().parse("E2"); + assertThat(baseExponent.getBase(), is(10)); + assertThat(baseExponent.getExponent(), is(2)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); + } + + @Test + public void testParseDecimalExponentPositive() { + final BaseExponent baseExponent = new SuffixFormatter().parse("e+3"); + assertThat(baseExponent.getBase(), is(10)); + assertThat(baseExponent.getExponent(), is(3)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); + } + + @Test + public void testParseDecimalExponentNegative() { + final BaseExponent baseExponent = new SuffixFormatter().parse("e-3"); + assertThat(baseExponent.getBase(), is(10)); + assertThat(baseExponent.getExponent(), is(-3)); + assertThat(baseExponent.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); + } + + @Test(expected = QuantityFormatException.class) + public void testParseBad() { + new SuffixFormatter().parse("eKi"); + } + + @Test + public void testFormatZeroDecimalExponent() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.DECIMAL_EXPONENT, 0); + assertThat(formattedString, is("")); + } + + @Test + public void testFormatDecimalExponent() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.DECIMAL_EXPONENT, 3); + assertThat(formattedString, is("e3")); + } + + @Test + public void testFormatZeroDecimalSi() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.DECIMAL_SI, 0); + assertThat(formattedString, is("")); + } + + @Test(expected = IllegalArgumentException.class) + public void testFormatBadDecimalSi() { + new SuffixFormatter().format(Quantity.Format.DECIMAL_SI, 2); + } + + @Test + public void testFormatDecimalSi() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.DECIMAL_SI, 3); + assertThat(formattedString, is("k")); + } + + @Test + public void testFormatNegativeDecimalSi() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.DECIMAL_SI, -6); + assertThat(formattedString, is("u")); + } + + @Test + public void testFormatBinarySi() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.BINARY_SI, 10); + assertThat(formattedString, is("Ki")); + } + + @Test + public void testFormatNoExponentBinarySi() { + final String formattedString = new SuffixFormatter().format(Quantity.Format.BINARY_SI, 0); + assertThat(formattedString, is("")); + } + + @Test(expected = IllegalArgumentException.class) + public void testFormatBadBinarySi() { + new SuffixFormatter().format(Quantity.Format.BINARY_SI, 4); + } + +} From 924458f0c75ed44166e962c0598f633386219742 Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 11:18:21 -0500 Subject: [PATCH 2/7] Use Commons Pair --- kubernetes/pom.xml | 4 + .../io/kubernetes/client/custom/Pair.java | 20 -- .../client/custom/QuantityFormatter.java | 10 +- pom.xml | 10 + util/pom.xml | 214 +++++++++--------- 5 files changed, 127 insertions(+), 131 deletions(-) delete mode 100644 kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java diff --git a/kubernetes/pom.xml b/kubernetes/pom.xml index bfe430cb8a..9a936b74f0 100644 --- a/kubernetes/pom.xml +++ b/kubernetes/pom.xml @@ -153,6 +153,10 @@ joda-time ${jodatime-version} + + org.apache.commons + commons-lang3 + junit diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java b/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java deleted file mode 100644 index 8925587e7d..0000000000 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/Pair.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.kubernetes.client.custom; - -public class Pair { - - private final L left; - private final R right; - - public Pair(final L left, final R right) { - this.left = left; - this.right = right; - } - - public L getLeft() { - return left; - } - - public R getRight() { - return right; - } -} diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java index 7f32a25a4a..6f6b3f982a 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java @@ -1,5 +1,7 @@ package io.kubernetes.client.custom; +import org.apache.commons.lang3.tuple.Pair; + import java.math.BigDecimal; import java.math.MathContext; @@ -68,11 +70,11 @@ private String toBase10String(final Quantity quantity) { private Pair ensureExponentIsMultipleOf3(final long mantissa, final int exponent) { final long exponentRemainder = exponent % 3; if (exponentRemainder == 1 || exponentRemainder == -2) { - return new Pair<>(mantissa * 10, exponent - 1); + return Pair.of(mantissa * 10, exponent - 1); } else if (exponentRemainder == -1 || exponentRemainder == 2) { - return new Pair<>(mantissa * 100, exponent - 2); + return Pair.of(mantissa * 100, exponent - 2); } else { - return new Pair<>(mantissa, exponent); + return Pair.of(mantissa, exponent); } } @@ -83,7 +85,7 @@ private Pair removeFactorsForBase(final long value, final int bas times++; result = result / base; } - return new Pair<>(result, times); + return Pair.of(result, times); } } diff --git a/pom.xml b/pom.xml index 41029a4180..ee9ab7619a 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,16 @@ + + + + org.apache.commons + commons-lang3 + 3.7 + + + + ossrh diff --git a/util/pom.xml b/util/pom.xml index 5d6a5bac41..e097ddf494 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -1,109 +1,109 @@ - - 4.0.0 - io.kubernetes - client-java - 1.0.0-beta2-SNAPSHOT - jar - client-java - https://github.com/kubernetes-client/java - - io.kubernetes - client-java-parent - 1.0.0-beta2-SNAPSHOT - - - - io.kubernetes - client-java-api - 1.0.0-beta2-SNAPSHOT - - - io.kubernetes - client-java-proto - 1.0.0-beta2-SNAPSHOT - - - org.yaml - snakeyaml - 1.18 - - - commons-codec - commons-codec - 1.10 - - - commons-lang - commons-lang - 2.6 - - - com.squareup.okhttp - okhttp-ws - 2.7.5 - - - com.google.guava - guava - 22.0 - - - log4j - log4j - 1.2.17 - - - - junit - junit - 4.12 - test - - - com.github.stefanbirkner - system-rules - 1.16.1 - - - com.google.protobuf - protobuf-java - 3.4.0 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.12 - - - - loggerPath - conf/log4j.properties - - - -Xms512m -Xmx1500m - methods - pertest - - - - - - 1.7 - ${java.version} - ${java.version} - 1.7.7 - + + 4.0.0 + io.kubernetes + client-java + 1.0.0-beta2-SNAPSHOT + jar + client-java + https://github.com/kubernetes-client/java + + io.kubernetes + client-java-parent + 1.0.0-beta2-SNAPSHOT + + + + io.kubernetes + client-java-api + 1.0.0-beta2-SNAPSHOT + + + io.kubernetes + client-java-proto + 1.0.0-beta2-SNAPSHOT + + + org.yaml + snakeyaml + 1.18 + + + commons-codec + commons-codec + 1.10 + + + org.apache.commons + commons-lang3 + + + com.squareup.okhttp + okhttp-ws + 2.7.5 + + + com.google.guava + guava + 22.0 + + + log4j + log4j + 1.2.17 + + + + junit + junit + 4.12 + test + + + com.github.stefanbirkner + system-rules + 1.16.1 + + + com.google.protobuf + protobuf-java + 3.4.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + + + 1.7 + ${java.version} + ${java.version} + 1.7.7 + From af94a84b4003e9b0180266bb4610a595912fe6ab Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 11:19:50 -0500 Subject: [PATCH 3/7] getBigDecimal -> getNumber --- .../java/io/kubernetes/client/custom/Quantity.java | 2 +- .../client/custom/QuantityFormatter.java | 8 ++++---- .../client/custom/QuantityFormatterTest.java | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java index 82e696051e..50bac66a14 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java @@ -33,7 +33,7 @@ public Quantity(final BigDecimal number, final Format format) { this.format = format; } - public BigDecimal getBigDecimal() { + public BigDecimal getNumber() { return number; } diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java index 6f6b3f982a..d39eec0207 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/QuantityFormatter.java @@ -37,7 +37,7 @@ public String format(final Quantity quantity) { return toBase10String(quantity); case BINARY_SI: if (isFractional(quantity)) { - return toBase10String(new Quantity(quantity.getBigDecimal(), Quantity.Format.DECIMAL_SI)); + return toBase10String(new Quantity(quantity.getNumber(), Quantity.Format.DECIMAL_SI)); } return toBase1024String(quantity); default: @@ -46,11 +46,11 @@ public String format(final Quantity quantity) { } private boolean isFractional(Quantity quantity) { - return quantity.getBigDecimal().scale() > 0; + return quantity.getNumber().scale() > 0; } private String toBase1024String(final Quantity quantity) { - final BigDecimal amount = quantity.getBigDecimal(); + final BigDecimal amount = quantity.getNumber(); final long value = amount.unscaledValue().longValue(); final int exponent = -amount.scale(); final Pair resultAndTimes = removeFactorsForBase(value, 1024); @@ -58,7 +58,7 @@ private String toBase1024String(final Quantity quantity) { } private String toBase10String(final Quantity quantity) { - final BigDecimal amount = quantity.getBigDecimal(); + final BigDecimal amount = quantity.getNumber(); final long value = amount.unscaledValue().longValue(); final int exponent = -amount.scale(); final Pair resultAndTimes = removeFactorsForBase(value, 10); diff --git a/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java index cd5bb8dfb4..3f1a075c5b 100644 --- a/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java +++ b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityFormatterTest.java @@ -13,49 +13,49 @@ public class QuantityFormatterTest { public void testParsePlain() { final Quantity quantity = new QuantityFormatter().parse("1"); assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(1))); } @Test public void testParseFractional() { final Quantity quantity = new QuantityFormatter().parse("0.001"); assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(0.001))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(0.001))); } @Test public void testParseFractionalUnit() { final Quantity quantity = new QuantityFormatter().parse("0.001m"); assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_SI)); - assertThat(quantity.getBigDecimal(), is(new BigDecimal("0.000001"))); + assertThat(quantity.getNumber(), is(new BigDecimal("0.000001"))); } @Test public void testParseBinarySi() { final Quantity quantity = new QuantityFormatter().parse("1Ki"); assertThat(quantity.getFormat(), is(Quantity.Format.BINARY_SI)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1024))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(1024))); } @Test public void testParseLargeNumeratorBinarySi() { final Quantity quantity = new QuantityFormatter().parse("32Mi"); assertThat(quantity.getFormat(), is(Quantity.Format.BINARY_SI)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(2).pow(20).multiply(BigDecimal.valueOf(32)))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(2).pow(20).multiply(BigDecimal.valueOf(32)))); } @Test public void testParseExponent() { final Quantity quantity = new QuantityFormatter().parse("1e3"); assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(1000))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(1000))); } @Test public void testParseNegativeExponent() { final Quantity quantity = new QuantityFormatter().parse("1e-3"); assertThat(quantity.getFormat(), is(Quantity.Format.DECIMAL_EXPONENT)); - assertThat(quantity.getBigDecimal(), is(BigDecimal.valueOf(0.001))); + assertThat(quantity.getNumber(), is(BigDecimal.valueOf(0.001))); } @Test(expected = QuantityFormatException.class) From cd4108d3ce3bdb9d368fe7fbea7e43816a18cbb0 Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 13:47:52 -0500 Subject: [PATCH 4/7] Update or remove imports --- .../java/io/kubernetes/client/Attach.java | 25 +++++-------- .../main/java/io/kubernetes/client/Exec.java | 35 ++++++++----------- .../java/io/kubernetes/client/PodLogs.java | 10 ------ 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/util/src/main/java/io/kubernetes/client/Attach.java b/util/src/main/java/io/kubernetes/client/Attach.java index 3520fbe9ac..b09f21023a 100644 --- a/util/src/main/java/io/kubernetes/client/Attach.java +++ b/util/src/main/java/io/kubernetes/client/Attach.java @@ -12,20 +12,13 @@ */ package io.kubernetes.client; -import io.kubernetes.client.Configuration; import io.kubernetes.client.models.V1Pod; import io.kubernetes.client.util.WebSockets; import io.kubernetes.client.util.WebSocketStreamHandler; -import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.Reader; - -import org.apache.commons.lang.StringUtils; public class Attach { private ApiClient apiClient; @@ -75,7 +68,7 @@ private String makePath(String namespace, String name, String container, boolean /** * Attach to a running AttachResult in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param namespace The namespace of the Pod * @param name The name of the Pod * @param stdin If true, pass a stdin stream into the container @@ -87,9 +80,9 @@ public AttachResult attach(String namespace, String name, boolean stdin) throws /** * Attach to a running AttachResult in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. - * @param stdin If true, pass a stdin stream into the container + * @param stdin If true, pass a stdin stream into the container */ public AttachResult attach(V1Pod pod, boolean stdin) throws ApiException, IOException { return attach(pod, stdin, false); @@ -99,9 +92,9 @@ public AttachResult attach(V1Pod pod, boolean stdin) throws ApiException, IOExce /** * Attach to a running AttachResult in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. - * @param stdin If true, pass a stdin stream into the container + * @param stdin If true, pass a stdin stream into the container * @param tty If true, stdin is a tty. */ public AttachResult attach(V1Pod pod, boolean stdin, boolean tty) throws ApiException, IOException { @@ -111,7 +104,7 @@ public AttachResult attach(V1Pod pod, boolean stdin, boolean tty) throws ApiExce /** * Attach to a running AttachResult in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. * @param container The container in the Pod where the command is run. * @param stdin If true, pass a stdin stream into the container. @@ -124,7 +117,7 @@ public AttachResult attach(V1Pod pod, String container, boolean stdin, boolean t /** * Attach to a running AttachResult in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param namespace The namespace of the Pod * @param name The name of the Pod * @param container The container in the Pod where the command is run. @@ -143,9 +136,9 @@ public AttachResult attach(String namespace, String name, String container, bool /** * AttachResult contains the result of an Attach call, it includes streams for stdout - * stderr and stdin. + * stderr and stdin. */ - public static class AttachResult implements java.io.Closeable { + public static class AttachResult implements java.io.Closeable { private WebSocketStreamHandler handler; diff --git a/util/src/main/java/io/kubernetes/client/Exec.java b/util/src/main/java/io/kubernetes/client/Exec.java index 67dfac7886..edb5dd2320 100644 --- a/util/src/main/java/io/kubernetes/client/Exec.java +++ b/util/src/main/java/io/kubernetes/client/Exec.java @@ -12,21 +12,14 @@ */ package io.kubernetes.client; -import io.kubernetes.client.Configuration; import io.kubernetes.client.models.V1Pod; import io.kubernetes.client.util.WebSocketStreamHandler; import io.kubernetes.client.util.WebSockets; +import org.apache.commons.lang3.StringUtils; -import java.io.ByteArrayInputStream; -import java.io.Closeable; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.Reader; - -import org.apache.commons.lang.StringUtils; public class Exec { private ApiClient apiClient; @@ -70,7 +63,7 @@ private String makePath(String namespace, String name, String[] command, String "/exec?" + "stdin=" + stdin + "&tty=" + tty + - (container != null ? "&container=" + container : "") + + (container != null ? "&container=" + container : "") + "&command=" + StringUtils.join(command, "&command="); return path; } @@ -78,7 +71,7 @@ private String makePath(String namespace, String name, String[] command, String /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param namespace The namespace of the Pod * @param name The name of the Pod * @param command The command to run @@ -91,10 +84,10 @@ public Process exec(String namespace, String name, String[] command, boolean std /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. * @param command The command to run - * @param stdin If true, pass a stdin stream into the container + * @param stdin If true, pass a stdin stream into the container */ public Process exec(V1Pod pod, String[] command, boolean stdin) throws ApiException, IOException { return exec(pod, command, null, stdin, false); @@ -103,11 +96,11 @@ public Process exec(V1Pod pod, String[] command, boolean stdin) throws ApiExcept /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param namespace The namespace of the Pod * @param name The name of the Pod * @param command The command to run - * @param stdin If true, pass a stdin stream into the container + * @param stdin If true, pass a stdin stream into the container * @param tty If true, stdin is a tty. */ public Process exec(String namespace, String name, String[] command, boolean stdin, boolean tty) throws ApiException, IOException { @@ -117,10 +110,10 @@ public Process exec(String namespace, String name, String[] command, boolean std /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. * @param command The command to run - * @param stdin If true, pass a stdin stream into the container + * @param stdin If true, pass a stdin stream into the container * @param tty If true, stdin is a tty. */ public Process exec(V1Pod pod, String[] command, boolean stdin, boolean tty) throws ApiException, IOException { @@ -130,7 +123,7 @@ public Process exec(V1Pod pod, String[] command, boolean stdin, boolean tty) thr /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param pod The pod where the command is run. * @param command The command to run * @param container The container in the Pod where the command is run. @@ -144,7 +137,7 @@ public Process exec(V1Pod pod, String[] command, String container, boolean stdin /** * Execute a command in a container. If there are multiple containers in the pod, uses * the first container in the Pod. - * + * * @param namespace The namespace of the Pod * @param name The name of the Pod * @param command The command to run @@ -166,7 +159,7 @@ private static class ExecProcess extends Process { WebSocketStreamHandler streamHandler; private int statusCode; - + public ExecProcess(WebSocketStreamHandler handler) throws IOException { this.streamHandler = handler; this.statusCode = -1; @@ -194,7 +187,7 @@ public int waitFor() throws InterruptedException { } return statusCode; } - + public int exitValue() { return statusCode; } @@ -202,5 +195,5 @@ public int exitValue() { public void destroy() { streamHandler.close(); } - } + } } \ No newline at end of file diff --git a/util/src/main/java/io/kubernetes/client/PodLogs.java b/util/src/main/java/io/kubernetes/client/PodLogs.java index fe44ff1bb0..8ac149597c 100644 --- a/util/src/main/java/io/kubernetes/client/PodLogs.java +++ b/util/src/main/java/io/kubernetes/client/PodLogs.java @@ -12,21 +12,11 @@ */ package io.kubernetes.client; -import io.kubernetes.client.Configuration; import io.kubernetes.client.apis.CoreV1Api; import io.kubernetes.client.models.V1Pod; -import io.kubernetes.client.util.WebSockets; -import io.kubernetes.client.util.WebSocketStreamHandler; -import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.Reader; - -import org.apache.commons.lang.StringUtils; import com.squareup.okhttp.Call; import com.squareup.okhttp.Response; From 6cf2c644513bab06d02af5e4cfab79fb95de873d Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 14:00:19 -0500 Subject: [PATCH 5/7] Simplify BaseExponent#equals --- .../main/java/io/kubernetes/client/custom/BaseExponent.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java index 44f850cf28..f184f031dc 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java @@ -41,9 +41,7 @@ public boolean equals(Object o) { BaseExponent that = (BaseExponent) o; - if (base != that.base) return false; - if (exponent != that.exponent) return false; - return format == that.format; + return base == that.base && exponent == that.exponent && format == that.format; } @Override From f37eee2566ea953f0593fb6b8bb24356ba7fb876 Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 14:03:54 -0500 Subject: [PATCH 6/7] Fix line-spacing --- .../main/java/io/kubernetes/client/custom/BaseExponent.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java index f184f031dc..12294d592e 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java @@ -3,11 +3,10 @@ public class BaseExponent { private final int base; - private final int exponent; - private final Quantity.Format format; - public BaseExponent(int base, int exponent, Quantity.Format format) { + + public BaseExponent(final int base, final int exponent, final Quantity.Format format) { this.base = base; this.exponent = exponent; this.format = format; From cb1bfc22c44213884c20b86158b63d1d7834fb79 Mon Sep 17 00:00:00 2001 From: Lewis Headden Date: Tue, 28 Nov 2017 14:16:17 -0500 Subject: [PATCH 7/7] Use String#hashCode instead of auto-generated one --- .../main/java/io/kubernetes/client/custom/BaseExponent.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java index 12294d592e..0793283ba7 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/BaseExponent.java @@ -45,9 +45,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = base; - result = 31 * result + exponent; - result = 31 * result + (format != null ? format.hashCode() : 0); - return result; + return this.toString().hashCode(); } }