Move Precondition.gwt.xml logic to Java.

This both makes the logic more Java developer friendly
but also enables us to share it across GWT & J2CL.

This patch removes JSNI flags as it is not used yet.

Change-Id: Ib19dc82c861631dd51767fb2d0d6f21a1d5e7b2a
diff --git a/user/super/com/google/gwt/emul/Preconditions.gwt.xml b/user/super/com/google/gwt/emul/Preconditions.gwt.xml
index 6948ea3..8fc04df 100644
--- a/user/super/com/google/gwt/emul/Preconditions.gwt.xml
+++ b/user/super/com/google/gwt/emul/Preconditions.gwt.xml
@@ -12,116 +12,23 @@
 <!-- implied. License for the specific language governing permissions and   -->
 <!-- limitations under the License.                                         -->
 
-<!-- Defines support configurable preconditions -->
+<!-- Defines configurable preconditions -->
 <module type="fileset">
 
-  <!--
- ┌────────┬─────────────────────────────────────────────────────┬───────────────────────────────┐
- │Group   │Description                                          │Common Exception Types         │
- ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
- │JSNI    │Checks related to arguments and return types of      │ClassCastException             │
- │        │JSNI methods. (Not implemented yet)                  │                               │
- ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
- │BOUNDS  │Checks related to the bound checking in collections. │IndexOutBoundsException        │
- │        │                                                     │ArrayIndexOutOfBoundsException │
- ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
- │API     │Checks related to the correct usage of APIs.         │IllegalStateException          │
- │        │                                                     │NoSuchElementException         │
- │        │                                                     │NullPointerException           │
- │        │                                                     │IllegalArgumentException       │
- │        │                                                     │ConcurrentModificationException│
- ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
- │TYPE    │Checks related to java type system.                  │ClassCastException             │
- │        │                                                     │ArrayStoreException            │
- ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
- │CRITICAL│Checks for cases where not failing-fast will keep    │IllegalArgumentException       │
- │        │the object in an inconsistent state and/or degrade   │                               │
- │        │debugging significantly. Currently disabling these   │                               │
- │        │checks is not supported.                             │                               │
- └────────┴─────────────────────────────────────────────────────┴───────────────────────────────┘
-  -->
-  <define-property name="jre.checks.jsni" values="ENABLED,DISABLED" />
-  <define-property name="jre.checks.bounds" values="ENABLED,DISABLED" />
-  <define-property name="jre.checks.api" values="ENABLED,DISABLED" />
-  <define-property name="jre.checks.type" values="ENABLED,DISABLED" />
-  <define-property name="jre.checks.critical" values="ENABLED" />
+  <define-property name="jre.checks.bounds" values="AUTO,ENABLED,DISABLED" />
+  <define-property name="jre.checks.api" values="AUTO,ENABLED,DISABLED" />
+  <define-property name="jre.checks.type" values="AUTO,ENABLED,DISABLED" />
+  <set-property name="jre.checks.bounds" value="AUTO" />
+  <set-property name="jre.checks.api" value="AUTO" />
+  <set-property name="jre.checks.type" value="AUTO" />
 
-
-  <!--
- ┌────────────────┬─────────┬──────────┬─────────┬─────────┬─────────┐
- │Check level     │  JSNI   │  BOUNDS  │   API   │  TYPE   │CRITICAL │
- ├────────────────┼─────────┼──────────┼─────────┼─────────┼─────────┤
- │Full            │    X    │    X     │    X    │    X    │    X    │
- ├────────────────┼─────────┼──────────┼─────────┼─────────┼─────────┤
- │Normal (default)│         │    X     │    X    │    X    │    X    │
- ├────────────────┼─────────┼──────────┼─────────┼─────────┼─────────┤
- │Optimized       │         │          │         │    X    │    X    │
- ├────────────────┼─────────┼──────────┼─────────┼─────────┼─────────┤
- │Minimal         │         │          │         │         │    X    │
- ├────────────────┼─────────┼──────────┼─────────┼─────────┼─────────┤
- │None (N/A yet)  │         │          │         │         │         │
- └────────────────┴─────────┴──────────┴─────────┴─────────┴─────────┘
-  -->
-  <define-property name="jre.checks.checkLevel" values="FULL,NORMAL,OPTIMIZED,MINIMAL" />
-
-
-  <!-- Associate individual checks with levels -->
-
-  <set-property name="jre.checks.jsni" value="DISABLED" />
-  <set-property name="jre.checks.jsni" value="ENABLED">
-    <any>
-      <when-property-is name="jre.checks.checkLevel" value="FULL" />
-    </any>
-  </set-property>
-
-  <set-property name="jre.checks.bounds" value="DISABLED" />
-  <set-property name="jre.checks.bounds" value="ENABLED">
-    <any>
-      <when-property-is name="jre.checks.checkLevel" value="FULL" />
-      <when-property-is name="jre.checks.checkLevel" value="NORMAL" />
-    </any>
-  </set-property>
-
-  <set-property name="jre.checks.api" value="DISABLED" />
-  <set-property name="jre.checks.api" value="ENABLED">
-    <any>
-      <when-property-is name="jre.checks.checkLevel" value="FULL" />
-      <when-property-is name="jre.checks.checkLevel" value="NORMAL" />
-    </any>
-  </set-property>
-
-
-  <set-property name="jre.checks.type" value="DISABLED" />
-  <set-property name="jre.checks.type" value="ENABLED">
-    <any>
-      <when-property-is name="jre.checks.checkLevel" value="FULL" />
-      <when-property-is name="jre.checks.checkLevel" value="NORMAL" />
-      <when-property-is name="jre.checks.checkLevel" value="OPTIMIZED" />
-    </any>
-  </set-property>
-
-  <!-- CRITICAL checking cannot be disabled for now.
-  <set-property name="jre.checks.critical" value="DISABLED" />
-  <set-property name="jre.checks.critical" value="ENABLED">
-    <any>
-      <when-property-is name="jre.checks.checkLevel" value="FULL" />
-      <when-property-is name="jre.checks.checkLevel" value="NORMAL" />
-      <when-property-is name="jre.checks.checkLevel" value="OPTIMIZED" />
-      <when-property-is name="jre.checks.checkLevel" value="MINIMAL" />
-    </any>
-  </set-property>
-  -->
-
-  <!-- End of associations -->
-
-
-  <!-- Default checkLevel is NORMAL -->
+  <define-property name="jre.checks.checkLevel" values="NORMAL,OPTIMIZED,MINIMAL" />
   <set-property name="jre.checks.checkLevel" value="NORMAL" />
 
   <define-property name="jre.checkedMode" values="ENABLED,DISABLED" />
-
   <set-property name="jre.checkedMode" value="DISABLED" />
   <set-property name="jre.checkedMode" value="ENABLED">
     <when-property-is name="jre.debugMode" value="ENABLED" />
   </set-property>
+
 </module>
diff --git a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
index 0f6300b..8adf867 100644
--- a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
+++ b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
@@ -15,6 +15,7 @@
  */
 package java.util;
 
+import javaemul.internal.InternalPreconditions;
 import javaemul.internal.JsUtils;
 
 /**
@@ -23,8 +24,7 @@
  */
 class ConcurrentModificationDetector {
 
-  private static final boolean API_CHECK =
-    System.getProperty("jre.checks.api", "ENABLED").equals("ENABLED");
+  private static final boolean API_CHECK = InternalPreconditions.isApiChecked();
 
   private static final String MOD_COUNT_PROPERTY = "_gwt_modCount";
 
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java b/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
index 56812ce..f6868fa 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/InternalPreconditions.java
@@ -15,21 +15,88 @@
  */
 package javaemul.internal;
 
+import static java.lang.System.getProperty;
+
 import java.util.NoSuchElementException;
 
 /**
  * A utility class that provides utility functions to do precondition checks inside GWT-SDK.
+ * <p>Following table summarizes the grouping of the checks:
+ * <pre>
+ * ┌────────┬─────────────────────────────────────────────────────┬───────────────────────────────┐
+ * │Group   │Description                                          │Common Exception Types         │
+ * ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
+ * │BOUNDS  │Checks related to the bound checking in collections. │IndexOutBoundsException        │
+ * │        │                                                     │ArrayIndexOutOfBoundsException │
+ * ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
+ * │API     │Checks related to the correct usage of APIs.         │IllegalStateException          │
+ * │        │                                                     │NoSuchElementException         │
+ * │        │                                                     │NullPointerException           │
+ * │        │                                                     │IllegalArgumentException       │
+ * │        │                                                     │ConcurrentModificationException│
+ * ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
+ * │TYPE    │Checks related to java type system.                  │ClassCastException             │
+ * │        │                                                     │ArrayStoreException            │
+ * ├────────┼─────────────────────────────────────────────────────┼───────────────────────────────┤
+ * │CRITICAL│Checks for cases where not failing-fast will keep    │IllegalArgumentException       │
+ * │        │the object in an inconsistent state and/or degrade   │                               │
+ * │        │debugging significantly. Currently disabling these   │                               │
+ * │        │checks is not supported.                             │                               │
+ * └────────┴─────────────────────────────────────────────────────┴───────────────────────────────┘
+ * </pre>
+ *
+ * <p> Following table summarizes predefined check levels:
+ * <pre>
+ * ┌────────────────┬──────────┬─────────┬─────────┬─────────┐
+ * │Check level     │  BOUNDS  │   API   │  TYPE   │CRITICAL │
+ * ├────────────────┼──────────┼─────────┼─────────┼─────────┤
+ * │Normal (default)│    X     │    X    │    X    │    X    │
+ * ├────────────────┼──────────┼─────────┼─────────┼─────────┤
+ * │Optimized       │          │         │    X    │    X    │
+ * ├────────────────┼──────────┼─────────┼─────────┼─────────┤
+ * │Minimal         │          │         │         │    X    │
+ * ├────────────────┼──────────┼─────────┼─────────┼─────────┤
+ * │None (N/A yet)  │          │         │         │         │
+ * └────────────────┴──────────┴─────────┴─────────┴─────────┘
+ * </pre>
+ *
+ * <p>Please note that, in development mode (jre.checkedMode=ENABLED), these checks will always be
+ * performed regardless of configuration but will be converted to AssertionError if check is
+ * disabled. This so that any reliance on related exceptions could be detected early on.
+ * For this detection to work properly; it is important for apps to share the same config in
+ * all environments.
  */
 // Some parts adapted from Guava
 public final class InternalPreconditions {
-  private static final boolean CHECKED_MODE =
-      System.getProperty("jre.checkedMode", "ENABLED").equals("ENABLED");
-  private static final boolean TYPE_CHECK =
-      System.getProperty("jre.checks.type", "ENABLED").equals("ENABLED");
-  private static final boolean API_CHECK =
-      System.getProperty("jre.checks.api", "ENABLED").equals("ENABLED");
-  private static final boolean BOUND_CHECK =
-      System.getProperty("jre.checks.bounds", "ENABLED").equals("ENABLED");
+
+  private static final String CHECK_TYPE = getProperty("jre.checks.type");
+  private static final String CHECK_BOUNDS = getProperty("jre.checks.bounds");
+  private static final String CHECK_API = getProperty("jre.checks.api");
+
+  // NORMAL
+  private static final boolean LEVEL_NORMAL_OR_HIGHER =
+      getProperty("jre.checks.checkLevel").equals("NORMAL");
+  // NORMAL or OPTIMIZED
+  private static final boolean LEVEL_OPT_OR_HIGHER =
+      getProperty("jre.checks.checkLevel").equals("OPTIMIZED") || LEVEL_NORMAL_OR_HIGHER;
+  // NORMAL or OPTIMIZED or MINIMAL
+  private static final boolean LEVEL_MINIMAL_OR_HIGHER =
+      getProperty("jre.checks.checkLevel").equals("MINIMAL") || LEVEL_OPT_OR_HIGHER;
+
+  static {
+    if (!LEVEL_MINIMAL_OR_HIGHER) {
+      throw new IllegalStateException("Incorrect level: " + getProperty("jre.checks.checkLevel"));
+    }
+  }
+
+  private static final boolean IS_TYPE_CHECKED =
+      (CHECK_TYPE.equals("AUTO") && LEVEL_OPT_OR_HIGHER) || CHECK_TYPE.equals("ENABLED");
+  private static final boolean IS_BOUNDS_CHECKED =
+      (CHECK_BOUNDS.equals("AUTO") && LEVEL_NORMAL_OR_HIGHER) || CHECK_BOUNDS.equals("ENABLED");
+  private static final boolean IS_API_CHECKED =
+      (CHECK_API.equals("AUTO") && LEVEL_NORMAL_OR_HIGHER) || CHECK_API.equals("ENABLED");
+
+  private static final boolean IS_ASSERTED = getProperty("jre.checkedMode").equals("ENABLED");
 
   /**
    * This method reports if the code is compiled with type checks.
@@ -39,13 +106,23 @@
    * Please note that {@link #checkType(boolean)} should be preferred where feasible.
    */
   public static boolean isTypeChecked() {
-    return TYPE_CHECK || CHECKED_MODE;
+    return IS_TYPE_CHECKED || IS_ASSERTED;
+  }
+
+  /**
+   * This method reports if the code is compiled with api checks.
+   * It must be used in places where code can be replaced with a simpler one
+   * when we know that no checks will occur.
+   * Please note that {@code #checkXXX(boolean)} should be preferred where feasible.
+   */
+  public static boolean isApiChecked() {
+    return IS_API_CHECKED || IS_ASSERTED;
   }
 
   public static void checkType(boolean expression) {
-    if (TYPE_CHECK) {
+    if (IS_TYPE_CHECKED) {
       checkCriticalType(expression);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalType(expression);
       } catch (Exception e) {
@@ -64,9 +141,9 @@
    * Ensures the truth of an expression that verifies array type.
    */
   public static void checkArrayType(boolean expression) {
-    if (TYPE_CHECK) {
+    if (IS_TYPE_CHECKED) {
       checkCriticalArrayType(expression);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArrayType(expression);
       } catch (Exception e) {
@@ -85,9 +162,9 @@
    * Ensures the truth of an expression that verifies array type.
    */
   public static void checkArrayType(boolean expression, Object errorMessage) {
-    if (TYPE_CHECK) {
+    if (IS_TYPE_CHECKED) {
       checkCriticalArrayType(expression, errorMessage);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArrayType(expression, errorMessage);
       } catch (Exception e) {
@@ -106,9 +183,9 @@
    * Ensures the truth of an expression involving existence of an element.
    */
   public static void checkElement(boolean expression) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalElement(expression);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalElement(expression);
       } catch (Exception e) {
@@ -133,9 +210,9 @@
    * Ensures the truth of an expression involving existence of an element.
    */
   public static void checkElement(boolean expression, Object errorMessage) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalElement(expression, errorMessage);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalElement(expression, errorMessage);
       } catch (Exception e) {
@@ -160,9 +237,9 @@
    * Ensures the truth of an expression involving one or more parameters to the calling method.
    */
   public static void checkArgument(boolean expression) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalArgument(expression);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArgument(expression);
       } catch (Exception e) {
@@ -187,9 +264,9 @@
    * Ensures the truth of an expression involving one or more parameters to the calling method.
    */
   public static void checkArgument(boolean expression, Object errorMessage) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalArgument(expression, errorMessage);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArgument(expression, errorMessage);
       } catch (Exception e) {
@@ -215,9 +292,9 @@
    */
   public static void checkArgument(boolean expression, String errorMessageTemplate,
       Object... errorMessageArgs) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalArgument(expression, errorMessageTemplate, errorMessageArgs);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArgument(expression, errorMessageTemplate, errorMessageArgs);
       } catch (Exception e) {
@@ -247,9 +324,9 @@
    * @throws IllegalStateException if {@code expression} is false
    */
   public static void checkState(boolean expression) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalState(expression);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalState(expression);
       } catch (Exception e) {
@@ -276,9 +353,9 @@
    * involving any parameters to the calling method.
    */
   public static void checkState(boolean expression, Object errorMessage) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalState(expression, errorMessage);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalState(expression, errorMessage);
       } catch (Exception e) {
@@ -301,9 +378,9 @@
    * Ensures that an object reference passed as a parameter to the calling method is not null.
    */
   public static <T> T checkNotNull(T reference) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalNotNull(reference);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalNotNull(reference);
       } catch (Exception e) {
@@ -325,9 +402,9 @@
    * Ensures that an object reference passed as a parameter to the calling method is not null.
    */
   public static void checkNotNull(Object reference, Object errorMessage) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalNotNull(reference, errorMessage);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalNotNull(reference, errorMessage);
       } catch (Exception e) {
@@ -346,9 +423,9 @@
    * Ensures that {@code size} specifies a valid array size (i.e. non-negative).
    */
   public static void checkArraySize(int size) {
-    if (API_CHECK) {
+    if (IS_API_CHECKED) {
       checkCriticalArraySize(size);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalArraySize(size);
       } catch (Exception e) {
@@ -368,9 +445,9 @@
    * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
    */
   public static void checkElementIndex(int index, int size) {
-    if (BOUND_CHECK) {
+    if (IS_BOUNDS_CHECKED) {
       checkCriticalElementIndex(index, size);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalElementIndex(index, size);
       } catch (Exception e) {
@@ -390,9 +467,9 @@
    * size {@code size}. A position index may range from zero to {@code size}, inclusive.
    */
   public static void checkPositionIndex(int index, int size) {
-    if (BOUND_CHECK) {
+    if (IS_BOUNDS_CHECKED) {
       checkCriticalPositionIndex(index, size);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalPositionIndex(index, size);
       } catch (Exception e) {
@@ -413,9 +490,9 @@
    * {@code size}, inclusive.
    */
   public static void checkPositionIndexes(int start, int end, int size) {
-    if (BOUND_CHECK) {
+    if (IS_BOUNDS_CHECKED) {
       checkCriticalPositionIndexes(start, end, size);
-    } else if (CHECKED_MODE) {
+    } else if (IS_ASSERTED) {
       try {
         checkCriticalPositionIndexes(start, end, size);
       } catch (Exception e) {