You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/05/07 02:12:25 UTC
[james-project] 01/22: JAMES-3140 Add a way of parsing Size units
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit e1e8c1234327da80a7dc22f5a0ddc11f1e4c0475
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Apr 28 08:42:20 2020 +0700
JAMES-3140 Add a way of parsing Size units
Reuse amount/unit separation of DurationParser.
---
.../java/org/apache/james/util/DurationParser.java | 35 ++----------
.../java/org/apache/james/util/SizeFormat.java | 25 ++++++++-
.../java/org/apache/james/util/UnitParser.java | 64 ++++++++++++++++++++++
.../java/org/apache/james/util/SizeFormatTest.java | 60 ++++++++++++++++++++
4 files changed, 153 insertions(+), 31 deletions(-)
diff --git a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
index a0d61a6..6194501 100644
--- a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
+++ b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
@@ -23,22 +23,11 @@ import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
-import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
public class DurationParser {
-
- private static final String PATTERN_STRING = "\\s*(-?[0-9]+)\\s*([a-z,A-Z]*)\\s*";
- private static final int AMOUNT = 1;
- private static final int UNIT = 2;
-
- private static Pattern PATTERN = Pattern.compile(PATTERN_STRING);
-
private enum Unit {
MILLI_SECONDS(ImmutableList.of("ms", "msec", "msecs"), ChronoUnit.MILLIS),
SECONDS(ImmutableList.of("s", "sec", "secs", "second", "seconds"), ChronoUnit.SECONDS),
@@ -86,18 +75,11 @@ public class DurationParser {
}
public static Duration parse(String rawString, ChronoUnit defaultUnit) throws NumberFormatException {
- Matcher res = PATTERN.matcher(rawString);
- if (res.matches()) {
- String unitAsString = res.group(UNIT);
- String amountAsString = res.group(AMOUNT);
- if (amountAsString != null && unitAsString != null) {
- long time = Integer.parseInt(res.group(AMOUNT).trim());
- Duration unitAsDuration = parseUnitAsDuration(unitAsString).orElse(defaultUnit.getDuration());
-
- return computeDuration(unitAsDuration, time);
- }
- }
- throw new NumberFormatException("The supplied String is not a supported format " + rawString);
+ UnitParser.ParsingResult parsingResult = UnitParser.parse(rawString);
+ Duration unitAsDuration = parsingResult.getUnit()
+ .map(s -> Unit.parse(s).getDuration())
+ .orElse(defaultUnit.getDuration());
+ return computeDuration(unitAsDuration, parsingResult.getNumber());
}
private static Duration computeDuration(Duration unitAsDuration, long time) {
@@ -105,11 +87,4 @@ public class DurationParser {
return unitAsDuration.multipliedBy(time);
}
-
- private static Optional<Duration> parseUnitAsDuration(String unit) {
- if (Strings.isNullOrEmpty(unit)) {
- return Optional.empty();
- }
- return Optional.of(Unit.parse(unit).getDuration());
- }
}
diff --git a/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java b/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
index c5293a8..c71ad3c 100644
--- a/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
+++ b/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
@@ -24,7 +24,9 @@ import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
+import java.util.Arrays;
import java.util.Locale;
+import java.util.Optional;
import org.apache.commons.io.FileUtils;
@@ -59,6 +61,12 @@ public class SizeFormat {
private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = new DecimalFormatSymbols(Locale.US);
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.##", DECIMAL_FORMAT_SYMBOLS);
+ public static Optional<Unit> of(String rawValue) {
+ return Arrays.stream(values())
+ .filter(unit -> unit.notation.equals(rawValue))
+ .findAny();
+ }
+
private final BigInteger bytesCount;
private final String notation;
@@ -67,6 +75,11 @@ public class SizeFormat {
this.notation = notation;
}
+ public long toByteCount(long value) {
+ return bytesCount.multiply(BigInteger.valueOf(value))
+ .longValueExact();
+ }
+
public String format(long size) {
return format(new BigDecimal(size));
}
@@ -76,7 +89,7 @@ public class SizeFormat {
}
public BigDecimal scaleToUnit(BigDecimal sizeAsDecimal) {
- return sizeAsDecimal.divide(new BigDecimal((bytesCount)), SCALE, RoundingMode.FLOOR);
+ return sizeAsDecimal.divide(new BigDecimal(bytesCount), SCALE, RoundingMode.FLOOR);
}
private String asString(BigDecimal bigDecimal) {
@@ -90,4 +103,14 @@ public class SizeFormat {
return Unit.locateUnit(bytesCount)
.format(bytesCount);
}
+
+ public static long parseAsByteCount(String bytesWithUnit) {
+ UnitParser.ParsingResult parsingResult = UnitParser.parse(bytesWithUnit);
+ Unit unit = parsingResult.getUnit()
+ .map(rawValue -> Unit.of(rawValue)
+ .orElseThrow(() -> new IllegalArgumentException("Unknown unit " + rawValue)))
+ .orElse(Unit.Byte);
+
+ return unit.toByteCount(parsingResult.getNumber());
+ }
}
diff --git a/server/container/util/src/main/java/org/apache/james/util/UnitParser.java b/server/container/util/src/main/java/org/apache/james/util/UnitParser.java
new file mode 100644
index 0000000..2f6e7d7
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/UnitParser.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you 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.apache.james.util;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.google.common.base.Strings;
+
+class UnitParser {
+ static class ParsingResult {
+ private final long number;
+ private final Optional<String> unit;
+
+ ParsingResult(long number, Optional<String> unit) {
+ this.number = number;
+ this.unit = unit;
+ }
+
+ public long getNumber() {
+ return number;
+ }
+
+ public Optional<String> getUnit() {
+ return unit;
+ }
+ }
+
+ private static final String PATTERN_STRING = "\\s*(-?[0-9]+)\\s*([a-z,A-Z]*)\\s*";
+ private static final int AMOUNT = 1;
+ private static final int UNIT = 2;
+
+ private static Pattern PATTERN = Pattern.compile(PATTERN_STRING);
+
+ static ParsingResult parse(String rawString) throws NumberFormatException {
+ Matcher res = PATTERN.matcher(rawString);
+ if (res.matches()) {
+ String unitAsString = res.group(UNIT);
+ String amountAsString = res.group(AMOUNT);
+ long amount = Integer.parseInt(amountAsString.trim());
+
+ return new ParsingResult(amount, Optional.of(unitAsString).filter(s -> !Strings.isNullOrEmpty(s)));
+ }
+ throw new NumberFormatException("Supplied value do not follow the unit format (number optionally suffixed with a string representing the unit");
+ }
+}
diff --git a/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java b/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
index 03c5a24..436e0c5 100644
--- a/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
+++ b/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
@@ -86,4 +86,64 @@ class SizeFormatTest {
.isEqualTo("1 TiB");
}
+ @Test
+ void parseAsByteCountShouldReturnCountWhenNoUnit() {
+ assertThat(SizeFormat.parseAsByteCount("36"))
+ .isEqualTo(36);
+ }
+
+ @Test
+ void parseAsByteCountShouldAcceptKiB() {
+ assertThat(SizeFormat.parseAsByteCount("36 KiB"))
+ .isEqualTo(36 * 1024);
+ }
+
+ @Test
+ void parseAsByteCountShouldAcceptZero() {
+ assertThat(SizeFormat.parseAsByteCount("0 KiB"))
+ .isEqualTo(0);
+ }
+
+ @Test
+ void parseAsByteCountShouldThrowOnInvalidUnit() {
+ assertThatThrownBy(() -> SizeFormat.parseAsByteCount("0 invalid"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseAsByteCountShouldThrowOnMissingAmount() {
+ assertThatThrownBy(() -> SizeFormat.parseAsByteCount("KiB"))
+ .isInstanceOf(NumberFormatException.class);
+ }
+
+ @Test
+ void parseAsByteCountShouldThrowWhenEmpty() {
+ assertThatThrownBy(() -> SizeFormat.parseAsByteCount(""))
+ .isInstanceOf(NumberFormatException.class);
+ }
+
+ @Test
+ void parseAsByteCountShouldThrowWhenUnitDoesNotMatchCase() {
+ assertThatThrownBy(() -> SizeFormat.parseAsByteCount("12 KIB"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void parseAsByteCountShouldAcceptNegativeValue() {
+ assertThat(SizeFormat.parseAsByteCount("-36 KiB"))
+ .isEqualTo(-36 * 1024);
+ }
+
+ @Test
+ void parseAsByteCountShouldAcceptMiB() {
+ assertThat(SizeFormat.parseAsByteCount("36 MiB"))
+ .isEqualTo(36 * 1024 * 1024);
+ }
+
+ @Test
+ void parseAsByteCountShouldAcceptGiB() {
+ assertThat(SizeFormat.parseAsByteCount("36 GiB"))
+ .isEqualTo(36L * 1024L * 1024L * 1024L);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org