This is an automated email from the ASF dual-hosted git repository.

mblow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit 6eb42a0ebf010b69c8f4e763d90f89cfbe46ea1a
Author: Michael Blow <mb...@apache.org>
AuthorDate: Wed Dec 9 10:11:00 2020 -0500

    [NO ISSUE][CONFIG] Avoid integer overflow on option parse
    
    - Do not use Integer.parseUnsignedInt() for nonnegative integer option 
parsing, as
      this will result in negative numbers for values > 0x7fffffff
    - Renamed (OptionTypes.)UNSIGNED_INTEGER to NONNEGATIVE_INTEGER for clarity
    - Add POSITIVE_INTEGER_BYTE_UNIT & POSITIVE_LONG_BYTE_UNIT option types
    
    (includes cherry-pick of commit 7a99fcefe3)
    
    Change-Id: I03bc9e92c2b6ce48977e93966f6cb9160c4df893
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/10003
    Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Michael Blow <mb...@apache.org>
    Reviewed-by: Murtadha Hubail <mhub...@apache.org>
---
 .../asterix/common/config/CompilerProperties.java  |   7 +-
 .../asterix/common/config/ExternalProperties.java  |  17 +-
 .../asterix/common/config/MetadataProperties.java  |   6 +-
 .../common/config/ReplicationProperties.java       |   4 +-
 .../asterix/common/config/StorageProperties.java   |   6 +-
 .../common/config/TransactionProperties.java       |   6 +-
 .../hyracks/control/common/config/OptionTypes.java | 271 ++++++++++++---------
 .../control/common/controllers/CCConfig.java       |  20 +-
 .../control/common/controllers/NCConfig.java       |  26 +-
 9 files changed, 202 insertions(+), 161 deletions(-)

diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
index 9428e6f..8860495 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
@@ -23,7 +23,6 @@ import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 import static org.apache.hyracks.util.StorageUtil.StorageUnit.KILOBYTE;
 import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
 
@@ -31,6 +30,7 @@ import 
org.apache.hyracks.algebricks.core.config.AlgebricksConfig;
 import org.apache.hyracks.api.config.IOption;
 import org.apache.hyracks.api.config.IOptionType;
 import org.apache.hyracks.api.config.Section;
+import org.apache.hyracks.control.common.config.OptionTypes;
 import org.apache.hyracks.util.StorageUtil;
 
 public class CompilerProperties extends AbstractProperties {
@@ -68,7 +68,10 @@ public class CompilerProperties extends AbstractProperties {
                         + "other integer values dictate the number of query 
execution parallel partitions. The system will "
                         + "fall back to use the number of all available CPU 
cores in the cluster as the degree of parallelism "
                         + "if the number set by a user is too large or too 
small"),
-        COMPILER_STRINGOFFSET(UNSIGNED_INTEGER, 0, "Position of a first 
character in a String/Binary (0 or 1)"),
+        COMPILER_STRINGOFFSET(
+                OptionTypes.getRangedIntegerType(0, 1),
+                0,
+                "Position of a first character in a String/Binary (0 or 1)"),
         COMPILER_SORT_PARALLEL(BOOLEAN, AlgebricksConfig.SORT_PARALLEL, 
"Enabling/Disabling full parallel sort"),
         COMPILER_SORT_SAMPLES(
                 POSITIVE_INTEGER,
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
index 1533c9f..642cbd6 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
@@ -19,9 +19,10 @@
 package org.apache.asterix.common.config;
 
 import static org.apache.hyracks.control.common.config.OptionTypes.LEVEL;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER_BYTE_UNIT;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
 import org.apache.hyracks.api.config.IOption;
 import org.apache.hyracks.api.config.IOptionType;
@@ -32,11 +33,11 @@ import org.apache.logging.log4j.Level;
 public class ExternalProperties extends AbstractProperties {
 
     public enum Option implements IOption {
-        WEB_PORT(UNSIGNED_INTEGER, 19001, "The listen port of the legacy query 
interface"),
-        WEB_QUERYINTERFACE_PORT(UNSIGNED_INTEGER, 19006, "The listen port of 
the query web interface"),
-        API_PORT(UNSIGNED_INTEGER, 19002, "The listen port of the API server"),
-        ACTIVE_PORT(UNSIGNED_INTEGER, 19003, "The listen port of the active 
server"),
-        NC_API_PORT(UNSIGNED_INTEGER, 19004, "The listen port of the node 
controller API server"),
+        WEB_PORT(NONNEGATIVE_INTEGER, 19001, "The listen port of the legacy 
query interface"),
+        WEB_QUERYINTERFACE_PORT(NONNEGATIVE_INTEGER, 19006, "The listen port 
of the query web interface"),
+        API_PORT(NONNEGATIVE_INTEGER, 19002, "The listen port of the API 
server"),
+        ACTIVE_PORT(NONNEGATIVE_INTEGER, 19003, "The listen port of the active 
server"),
+        NC_API_PORT(NONNEGATIVE_INTEGER, 19004, "The listen port of the node 
controller API server"),
         LOG_LEVEL(LEVEL, Level.WARN, "The logging level for master and slave 
processes"),
         MAX_WAIT_ACTIVE_CLUSTER(
                 POSITIVE_INTEGER,
@@ -46,10 +47,10 @@ public class ExternalProperties extends AbstractProperties {
         CC_JAVA_OPTS(STRING, "-Xmx1024m", "The JVM options passed to the 
cluster controller process by managix"),
         NC_JAVA_OPTS(STRING, "-Xmx1024m", "The JVM options passed to the node 
controller process(es) by managix"),
         MAX_WEB_REQUEST_SIZE(
-                UNSIGNED_INTEGER,
+                POSITIVE_INTEGER_BYTE_UNIT,
                 StorageUtil.getIntSizeInBytes(50, 
StorageUtil.StorageUnit.MEGABYTE),
                 "The maximum accepted web request size in bytes"),
-        REQUESTS_ARCHIVE_SIZE(UNSIGNED_INTEGER, 50, "The maximum number of 
archived requests to maintain");
+        REQUESTS_ARCHIVE_SIZE(NONNEGATIVE_INTEGER, 50, "The maximum number of 
archived requests to maintain");
 
         private final IOptionType type;
         private final Object defaultValue;
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
index 7a3e707..7d5ec42 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
@@ -18,9 +18,9 @@
  */
 package org.apache.asterix.common.config;
 
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
 import java.util.List;
 import java.util.Map;
@@ -37,8 +37,8 @@ public class MetadataProperties extends AbstractProperties {
     public enum Option implements IOption {
         METADATA_NODE(STRING, null),
         METADATA_REGISTRATION_TIMEOUT_SECS(POSITIVE_INTEGER, 60),
-        METADATA_LISTEN_PORT(UNSIGNED_INTEGER, 0),
-        METADATA_CALLBACK_PORT(UNSIGNED_INTEGER, 0);
+        METADATA_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
+        METADATA_CALLBACK_PORT(NONNEGATIVE_INTEGER, 0);
 
         private final IOptionType type;
         private final Object defaultValue;
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
index 6082f30..dd42936 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
@@ -21,9 +21,9 @@ package org.apache.asterix.common.config;
 import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
 import java.util.concurrent.TimeUnit;
 
@@ -51,7 +51,7 @@ public class ReplicationProperties extends AbstractProperties 
{
                 TimeUnit.SECONDS.toSeconds(30),
                 "The time in seconds to timeout waiting for master or replica 
to ack"),
         REPLICATION_ENABLED(BOOLEAN, false, "Whether or not data replication 
is enabled"),
-        REPLICATION_FACTOR(UNSIGNED_INTEGER, 2, "Number of replicas (backups) 
to maintain per master replica"),
+        REPLICATION_FACTOR(NONNEGATIVE_INTEGER, 2, "Number of replicas 
(backups) to maintain per master replica"),
         REPLICATION_STRATEGY(STRING, "none", "Replication strategy to choose");
 
         private final IOptionType type;
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
index 58bc828..0bea099 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
@@ -21,9 +21,9 @@ package org.apache.asterix.common.config;
 import static org.apache.hyracks.control.common.config.OptionTypes.DOUBLE;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 import static org.apache.hyracks.util.StorageUtil.StorageUnit.KILOBYTE;
 import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
 
@@ -43,13 +43,13 @@ public class StorageProperties extends AbstractProperties {
         STORAGE_BUFFERCACHE_PAGESIZE(INTEGER_BYTE_UNIT, 
StorageUtil.getIntSizeInBytes(128, KILOBYTE)),
         // By default, uses 1/4 of the maximum heap size for read cache, i.e., 
disk buffer cache.
         STORAGE_BUFFERCACHE_SIZE(LONG_BYTE_UNIT, 
Runtime.getRuntime().maxMemory() / 4),
-        STORAGE_BUFFERCACHE_MAXOPENFILES(UNSIGNED_INTEGER, Integer.MAX_VALUE),
+        STORAGE_BUFFERCACHE_MAXOPENFILES(NONNEGATIVE_INTEGER, 
Integer.MAX_VALUE),
         STORAGE_MEMORYCOMPONENT_GLOBALBUDGET(LONG_BYTE_UNIT, 
Runtime.getRuntime().maxMemory() / 4),
         STORAGE_MEMORYCOMPONENT_PAGESIZE(INTEGER_BYTE_UNIT, 
StorageUtil.getIntSizeInBytes(128, KILOBYTE)),
         STORAGE_MEMORYCOMPONENT_NUMCOMPONENTS(POSITIVE_INTEGER, 2),
         STORAGE_METADATA_MEMORYCOMPONENT_NUMPAGES(POSITIVE_INTEGER, 8),
         STORAGE_LSM_BLOOMFILTER_FALSEPOSITIVERATE(DOUBLE, 0.01d),
-        STORAGE_MAX_ACTIVE_WRITABLE_DATASETS(UNSIGNED_INTEGER, 8),
+        STORAGE_MAX_ACTIVE_WRITABLE_DATASETS(POSITIVE_INTEGER, 8),
         STORAGE_COMPRESSION_BLOCK(STRING, "snappy"),
         STORAGE_DISK_FORCE_BYTES(LONG_BYTE_UNIT, 
StorageUtil.getLongSizeInBytes(16, MEGABYTE)),
         STORAGE_IO_SCHEDULER(STRING, "greedy");
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
index 5ed069c..f813ac3 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
@@ -21,8 +21,8 @@ package org.apache.asterix.common.config;
 import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
 
 import java.util.Map;
@@ -59,9 +59,9 @@ public class TransactionProperties extends AbstractProperties 
{
                 120,
                 "The frequency (in seconds) the checkpoint thread should check 
to see if a checkpoint should be "
                         + "written"),
-        TXN_LOG_CHECKPOINT_HISTORY(UNSIGNED_INTEGER, 2, "The number of 
checkpoints to keep in the transaction log"),
+        TXN_LOG_CHECKPOINT_HISTORY(NONNEGATIVE_INTEGER, 2, "The number of 
checkpoints to keep in the transaction log"),
         TXN_LOCK_ESCALATIONTHRESHOLD(
-                UNSIGNED_INTEGER,
+                NONNEGATIVE_INTEGER,
                 1000,
                 "The maximum number of entity locks to obtain before upgrading 
to a dataset lock"),
         TXN_LOCK_SHRINKTIMER(
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
index 7088e08..332d65b 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
@@ -33,66 +33,11 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public class OptionTypes {
 
-    public static final IOptionType<Integer> INTEGER_BYTE_UNIT = new 
IOptionType<Integer>() {
-        @Override
-        public Integer parse(String s) {
-            if (s == null) {
-                return null;
-            }
-            long result1 = StorageUtil.getByteValue(s);
-            if (result1 > Integer.MAX_VALUE || result1 < Integer.MIN_VALUE) {
-                throw new IllegalArgumentException("The given value: " + 
result1 + " is not within the int range.");
-            }
-            return (int) result1;
-        }
-
-        @Override
-        public Integer parse(JsonNode node) {
-            return node.isNull() ? null : parse(node.asText());
-        }
-
-        @Override
-        public Class<Integer> targetType() {
-            return Integer.class;
-        }
-
-        @Override
-        public String serializeToHumanReadable(Object value) {
-            return value + " (" + StorageUtil.toHumanReadableSize((int) value) 
+ ")";
-        }
-
-        @Override
-        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
-            node.put(fieldName, (int) value);
-        }
-    };
-
-    public static final IOptionType<Long> LONG_BYTE_UNIT = new 
IOptionType<Long>() {
-        @Override
-        public Long parse(String s) {
-            return s == null ? null : StorageUtil.getByteValue(s);
-        }
-
-        @Override
-        public Long parse(JsonNode node) {
-            return node.isNull() ? null : parse(node.asText());
-        }
-
-        @Override
-        public Class<Long> targetType() {
-            return Long.class;
-        }
-
-        @Override
-        public String serializeToHumanReadable(Object value) {
-            return value + " (" + StorageUtil.toHumanReadableSize((long) 
value) + ")";
-        }
+    public static final IOptionType<Integer> INTEGER_BYTE_UNIT = new 
IntegerByteUnit();
+    public static final IOptionType<Integer> POSITIVE_INTEGER_BYTE_UNIT = new 
IntegerByteUnit(1, Integer.MAX_VALUE);
 
-        @Override
-        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
-            node.put(fieldName, (long) value);
-        }
-    };
+    public static final IOptionType<Long> LONG_BYTE_UNIT = new LongByteUnit();
+    public static final IOptionType<Long> POSITIVE_LONG_BYTE_UNIT = new 
LongByteUnit(1, Long.MAX_VALUE);
 
     public static final IOptionType<Short> SHORT = new IOptionType<Short>() {
         @Override
@@ -124,27 +69,7 @@ public class OptionTypes {
         }
     };
 
-    public static final IOptionType<Integer> INTEGER = new 
IOptionType<Integer>() {
-        @Override
-        public Integer parse(String s) {
-            return Integer.parseInt(s);
-        }
-
-        @Override
-        public Integer parse(JsonNode node) {
-            return node.isNull() ? null : node.asInt();
-        }
-
-        @Override
-        public Class<Integer> targetType() {
-            return Integer.class;
-        }
-
-        @Override
-        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
-            node.put(fieldName, (int) value);
-        }
-    };
+    public static final IOptionType<Integer> INTEGER = new IntegerOptionType();
 
     public static final IOptionType<Double> DOUBLE = new IOptionType<Double>() 
{
         @Override
@@ -190,27 +115,7 @@ public class OptionTypes {
         }
     };
 
-    public static final IOptionType<Long> LONG = new IOptionType<Long>() {
-        @Override
-        public Long parse(String s) {
-            return Long.parseLong(s);
-        }
-
-        @Override
-        public Long parse(JsonNode node) {
-            return node.isNull() ? null : node.asLong();
-        }
-
-        @Override
-        public Class<Long> targetType() {
-            return Long.class;
-        }
-
-        @Override
-        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
-            node.put(fieldName, (long) value);
-        }
-    };
+    public static final IOptionType<Long> LONG = new LongOptionType();
 
     public static final IOptionType<Boolean> BOOLEAN = new 
IOptionType<Boolean>() {
         @Override
@@ -287,7 +192,7 @@ public class OptionTypes {
             List<String> strings = new ArrayList<>();
             if (node instanceof ArrayNode) {
                 node.elements().forEachRemaining(n -> strings.add(n.asText()));
-                return strings.toArray(new String[strings.size()]);
+                return strings.toArray(new String[0]);
             } else {
                 return parse(node.asText());
             }
@@ -340,15 +245,26 @@ public class OptionTypes {
         }
     };
 
-    public static final IOptionType<Integer> UNSIGNED_INTEGER = new 
IOptionType<Integer>() {
+    public static final IOptionType<Integer> NONNEGATIVE_INTEGER = 
getRangedIntegerType(0, Integer.MAX_VALUE);
+
+    public static final IOptionType<Integer> POSITIVE_INTEGER = 
getRangedIntegerType(1, Integer.MAX_VALUE);
+
+    private OptionTypes() {
+    }
+
+    public static IOptionType<Integer> getRangedIntegerType(final int 
minValueInclusive, final int maxValueInclusive) {
+        return new RangedIntegerOptionType(minValueInclusive, 
maxValueInclusive);
+    }
+
+    public static class IntegerOptionType implements IOptionType<Integer> {
         @Override
         public Integer parse(String s) {
-            return Integer.parseUnsignedInt(s);
+            return Integer.parseInt(s);
         }
 
         @Override
         public Integer parse(JsonNode node) {
-            return node.isNull() ? null : parse(node.asText());
+            return node.isNull() ? null : node.asInt();
         }
 
         @Override
@@ -360,34 +276,155 @@ public class OptionTypes {
         public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
             node.put(fieldName, (int) value);
         }
-    };
+    }
+
+    private static class RangedIntegerOptionType extends IntegerOptionType {
+        private final int minValue;
+        private final int maxValue;
+
+        RangedIntegerOptionType(int minValue, int maxValue) {
+            this.minValue = minValue;
+            this.maxValue = maxValue;
+        }
+
+        @Override
+        public Integer parse(String value) {
+            int intValue = super.parse(value);
+            rangeCheck(intValue);
+            return intValue;
+        }
+
+        void rangeCheck(long intValue) {
+            if (intValue < minValue || intValue > maxValue) {
+                if (maxValue == Integer.MAX_VALUE) {
+                    if (minValue == 0) {
+                        throw new IllegalArgumentException("integer value must 
not be negative, but was " + intValue);
+                    } else if (minValue == 1) {
+                        throw new IllegalArgumentException(
+                                "integer value must be greater than zero, but 
was " + intValue);
+                    }
+                }
+                throw new IllegalArgumentException(
+                        "integer value must be between " + minValue + "-" + 
maxValue + " (inclusive)");
+            }
+        }
+    }
+
+    private static class IntegerByteUnit extends RangedIntegerOptionType {
+
+        IntegerByteUnit() {
+            this(Integer.MIN_VALUE, Integer.MAX_VALUE);
+        }
+
+        IntegerByteUnit(int minValue, int maxValue) {
+            super(minValue, maxValue);
+        }
 
-    public static final IOptionType<Integer> POSITIVE_INTEGER = new 
IOptionType<Integer>() {
         @Override
         public Integer parse(String s) {
-            final int value = Integer.parseUnsignedInt(s);
-            if (value == 0) {
-                throw new IllegalArgumentException("Value must be greater than 
zero");
+            if (s == null) {
+                return null;
             }
-            return value;
+            long result = StorageUtil.getByteValue(s);
+            rangeCheck(result);
+            return (int) result;
         }
 
         @Override
         public Integer parse(JsonNode node) {
+            // TODO: we accept human readable sizes from json- why not emit 
human readable sizes?
             return node.isNull() ? null : parse(node.asText());
         }
 
         @Override
-        public Class<Integer> targetType() {
-            return Integer.class;
+        public String serializeToHumanReadable(Object value) {
+            return value + " (" + StorageUtil.toHumanReadableSize((int) value) 
+ ")";
+        }
+    }
+
+    private static class RangedLongOptionType extends LongOptionType {
+        private final long minValue;
+        private final long maxValue;
+
+        RangedLongOptionType(long minValue, long maxValue) {
+            this.minValue = minValue;
+            this.maxValue = maxValue;
         }
 
         @Override
-        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
-            node.put(fieldName, (int) value);
+        public Long parse(String value) {
+            long longValue = super.parse(value);
+            rangeCheck(longValue);
+            return longValue;
         }
-    };
 
-    private OptionTypes() {
+        void rangeCheck(long longValue) {
+            if (longValue < minValue || longValue > maxValue) {
+                if (maxValue == Long.MAX_VALUE) {
+                    if (minValue == 0) {
+                        throw new IllegalArgumentException("long value must 
not be negative, but was " + longValue);
+                    } else if (minValue == 1) {
+                        throw new IllegalArgumentException(
+                                "long value must be greater than zero, but was 
" + longValue);
+                    }
+                }
+                throw new IllegalArgumentException(
+                        "long value must be between " + minValue + "-" + 
maxValue + " (inclusive)");
+            }
+        }
+    }
+
+    private static class LongByteUnit extends RangedLongOptionType {
+
+        LongByteUnit() {
+            this(Long.MIN_VALUE, Long.MAX_VALUE);
+        }
+
+        LongByteUnit(long minValue, long maxValue) {
+            super(minValue, maxValue);
+        }
+
+        @Override
+        public Long parse(String s) {
+            if (s == null) {
+                return null;
+            }
+            long result = StorageUtil.getByteValue(s);
+            rangeCheck(result);
+            return result;
+        }
+
+        @Override
+        public Long parse(JsonNode node) {
+            // TODO: we accept human readable sizes from json- why not emit 
human readable sizes?
+            return node.isNull() ? null : parse(node.asText());
+        }
+
+        @Override
+        public String serializeToHumanReadable(Object value) {
+            return value + " (" + StorageUtil.toHumanReadableSize((long) 
value) + ")";
+        }
+    }
+
+    private static class LongOptionType implements IOptionType<Long> {
+        @Override
+        public Long parse(String s) {
+            return Long.parseLong(s);
+        }
+
+        @Override
+        public Long parse(JsonNode node) {
+            return node.isNull() ? null : node.asLong();
+        }
+
+        @Override
+        public Class<Long> targetType() {
+            return Long.class;
+        }
+
+        @Override
+        public void serializeJSONField(String fieldName, Object value, 
ObjectNode node) {
+            node.put(fieldName, (long) value);
+        }
     }
 }
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
index 0de75d9..17be02e 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
@@ -20,10 +20,10 @@ package org.apache.hyracks.control.common.controllers;
 
 import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
 import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.SHORT;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
 import java.io.File;
 import java.net.InetAddress;
@@ -49,22 +49,22 @@ public class CCConfig extends ControllerConfig {
         ADDRESS(STRING, InetAddress.getLoopbackAddress().getHostAddress()),
         PUBLIC_ADDRESS(STRING, ADDRESS),
         CLUSTER_LISTEN_ADDRESS(STRING, ADDRESS),
-        CLUSTER_LISTEN_PORT(UNSIGNED_INTEGER, 1099),
+        CLUSTER_LISTEN_PORT(NONNEGATIVE_INTEGER, 1099),
         CLUSTER_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        CLUSTER_PUBLIC_PORT(UNSIGNED_INTEGER, CLUSTER_LISTEN_PORT),
+        CLUSTER_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLUSTER_LISTEN_PORT),
         CLIENT_LISTEN_ADDRESS(STRING, ADDRESS),
-        CLIENT_LISTEN_PORT(UNSIGNED_INTEGER, 1098),
+        CLIENT_LISTEN_PORT(NONNEGATIVE_INTEGER, 1098),
         CLIENT_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        CLIENT_PUBLIC_PORT(UNSIGNED_INTEGER, CLIENT_LISTEN_PORT),
+        CLIENT_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLIENT_LISTEN_PORT),
         CONSOLE_LISTEN_ADDRESS(STRING, ADDRESS),
-        CONSOLE_LISTEN_PORT(UNSIGNED_INTEGER, 16001),
+        CONSOLE_LISTEN_PORT(NONNEGATIVE_INTEGER, 16001),
         CONSOLE_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        CONSOLE_PUBLIC_PORT(UNSIGNED_INTEGER, CONSOLE_LISTEN_PORT),
+        CONSOLE_PUBLIC_PORT(NONNEGATIVE_INTEGER, CONSOLE_LISTEN_PORT),
         HEARTBEAT_PERIOD(LONG, 10000L), // TODO (mblow): add time unit
-        HEARTBEAT_MAX_MISSES(UNSIGNED_INTEGER, 5),
+        HEARTBEAT_MAX_MISSES(NONNEGATIVE_INTEGER, 5),
         DEAD_NODE_SWEEP_THRESHOLD(LONG, HEARTBEAT_PERIOD),
-        PROFILE_DUMP_PERIOD(UNSIGNED_INTEGER, 0),
-        JOB_HISTORY_SIZE(UNSIGNED_INTEGER, 10),
+        PROFILE_DUMP_PERIOD(NONNEGATIVE_INTEGER, 0),
+        JOB_HISTORY_SIZE(NONNEGATIVE_INTEGER, 10),
         RESULT_TTL(LONG, 86400000L), // TODO(mblow): add time unit
         RESULT_SWEEP_THRESHOLD(LONG, 60000L), // TODO(mblow): add time unit
         @SuppressWarnings("RedundantCast") // not redundant- false positive 
from IDEA
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
index e947d7a..ef244c5 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
@@ -21,10 +21,10 @@ package org.apache.hyracks.control.common.controllers;
 import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static 
org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
 import static 
org.apache.hyracks.control.common.config.OptionTypes.STRING_ARRAY;
-import static 
org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -45,31 +45,31 @@ public class NCConfig extends ControllerConfig {
         ADDRESS(STRING, InetAddress.getLoopbackAddress().getHostAddress()),
         PUBLIC_ADDRESS(STRING, ADDRESS),
         CLUSTER_LISTEN_ADDRESS(STRING, ADDRESS),
-        CLUSTER_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+        CLUSTER_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
         NCSERVICE_ADDRESS(STRING, PUBLIC_ADDRESS),
         NCSERVICE_PORT(INTEGER, 9090),
         CLUSTER_ADDRESS(STRING, (String) null),
-        CLUSTER_PORT(UNSIGNED_INTEGER, 1099),
+        CLUSTER_PORT(NONNEGATIVE_INTEGER, 1099),
         CLUSTER_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        CLUSTER_PUBLIC_PORT(UNSIGNED_INTEGER, CLUSTER_LISTEN_PORT),
+        CLUSTER_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLUSTER_LISTEN_PORT),
         NODE_ID(STRING, (String) null),
         DATA_LISTEN_ADDRESS(STRING, ADDRESS),
-        DATA_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+        DATA_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
         DATA_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        DATA_PUBLIC_PORT(UNSIGNED_INTEGER, DATA_LISTEN_PORT),
+        DATA_PUBLIC_PORT(NONNEGATIVE_INTEGER, DATA_LISTEN_PORT),
         RESULT_LISTEN_ADDRESS(STRING, ADDRESS),
-        RESULT_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+        RESULT_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
         RESULT_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        RESULT_PUBLIC_PORT(UNSIGNED_INTEGER, RESULT_LISTEN_PORT),
+        RESULT_PUBLIC_PORT(NONNEGATIVE_INTEGER, RESULT_LISTEN_PORT),
         MESSAGING_LISTEN_ADDRESS(STRING, ADDRESS),
-        MESSAGING_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+        MESSAGING_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
         MESSAGING_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        MESSAGING_PUBLIC_PORT(UNSIGNED_INTEGER, MESSAGING_LISTEN_PORT),
+        MESSAGING_PUBLIC_PORT(NONNEGATIVE_INTEGER, MESSAGING_LISTEN_PORT),
         REPLICATION_LISTEN_ADDRESS(STRING, ADDRESS),
-        REPLICATION_LISTEN_PORT(UNSIGNED_INTEGER, 2000),
+        REPLICATION_LISTEN_PORT(NONNEGATIVE_INTEGER, 2000),
         REPLICATION_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        REPLICATION_PUBLIC_PORT(UNSIGNED_INTEGER, REPLICATION_LISTEN_PORT),
-        CLUSTER_CONNECT_RETRIES(UNSIGNED_INTEGER, 5),
+        REPLICATION_PUBLIC_PORT(NONNEGATIVE_INTEGER, REPLICATION_LISTEN_PORT),
+        CLUSTER_CONNECT_RETRIES(NONNEGATIVE_INTEGER, 5),
         IODEVICES(
                 STRING_ARRAY,
                 appConfig -> new String[] {

Reply via email to