package com.mopub.common; import android.os.Looper; import com.mopub.common.logging.MoPubLog; import java.util.IllegalFormatException; /** * Simple static methods to be called at the start of your own methods to verify correct arguments * and state. * * Each method supports 2 flavors - one that will always throw a runtime exception, and a NoThrow * version that will only throw an exception when in strict mode. We use the former * for internal state checks, and the later to validate arguments passed to the SDK. */ public final class Preconditions { public static final String EMPTY_ARGUMENTS = ""; private Preconditions() { // Non-instantiable. } /** * Ensures the truth of an expression. */ public static void checkArgument(boolean expression) { checkArgumentInternal(expression, true, "Illegal argument.", EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression, with an error message. */ public static void checkArgument(boolean expression, String errorMessage) { checkArgumentInternal(expression, true, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression, with an error message that takes arguments. */ public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { checkArgumentInternal(expression, true, errorMessageTemplate, errorMessageArgs); } /** * Ensures the truth of an expression involving the state of the caller. */ public static void checkState(boolean expression) { checkStateInternal(expression, true, "Illegal state.", EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression involving the state of the caller, with an error message. */ public static void checkState(boolean expression, String errorMessage) { checkStateInternal(expression, true, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression involving the state of the caller, with an error message * that takes arguments. */ public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { checkStateInternal(expression, true, errorMessageTemplate, errorMessageArgs); } /** * Ensures that an object reference is not null. */ public static void checkNotNull(Object reference) { checkNotNullInternal(reference, true, "Object can not be null.", EMPTY_ARGUMENTS); } /** * Ensures that an object reference is not null, with an error message. */ public static void checkNotNull(Object reference, String errorMessage) { checkNotNullInternal(reference, true, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures that an object reference is not null, with an error message that takes arguments. */ public static void checkNotNull(Object reference, String errorMessageTemplate, Object... errorMessageArgs) { checkNotNullInternal(reference, true, errorMessageTemplate, errorMessageArgs); } /** * Ensures that the current thread is the UI thread. */ public static void checkUiThread() { checkUiThreadInternal(true, "This method must be called from the UI thread.", EMPTY_ARGUMENTS); } /** * Ensures that the current thread is the UI thread, with an error message. */ public static void checkUiThread(String errorMessage) { checkUiThreadInternal(true, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures that the current thread is the UI thread, with an error message that takes * arguments. */ public static void checkUiThread(String errorMessageTemplate, Object... errorMessageArgs) { checkUiThreadInternal(true, errorMessageTemplate, errorMessageArgs); } /** * Preconditions checks that avoid throwing and exception in release mode. These versions return * a boolean which the caller should check. */ public final static class NoThrow { private static volatile boolean sStrictMode = false; /** * Enables or disables strict mode. * * In strict mode, this class will throw anyway. For example, you could set strict mode to * BuildConfig.DEBUG to always get exceptions when in the IDE. * * @param strictMode Whether to use strict mode. */ public static void setStrictMode(boolean strictMode) { sStrictMode = strictMode; } /** * Ensures the truth of an expression. */ public static boolean checkArgument(boolean expression) { return checkArgumentInternal(expression, sStrictMode, "Illegal argument", EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression, with an error message. */ public static boolean checkArgument(boolean expression, String errorMessage) { return checkArgumentInternal(expression, sStrictMode, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression, with an error message that takes arguments. */ public static boolean checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { return checkArgumentInternal(expression, sStrictMode, errorMessageTemplate, errorMessageArgs); } /** * Ensures the truth of an expression involving the state of the caller. */ public static boolean checkState(boolean expression) { return checkStateInternal(expression, sStrictMode, "Illegal state.", EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression involving the state of the caller, with an error * message. */ public static boolean checkState(boolean expression, String errorMessage) { return checkStateInternal(expression, sStrictMode, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures the truth of an expression involving the state of the caller, with an error * message that takes arguments. */ public static boolean checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { return checkStateInternal(expression, sStrictMode, errorMessageTemplate, errorMessageArgs); } /** * Ensures that an object reference is not null. */ public static boolean checkNotNull(Object reference) { return checkNotNullInternal(reference, sStrictMode, "Object can not be null.", EMPTY_ARGUMENTS); } /** * Ensures that an object reference is not null, with an error message. */ public static boolean checkNotNull(Object reference, String errorMessage) { return checkNotNullInternal(reference, sStrictMode, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures that an object reference is not null, with an error message that takes * arguments. */ public static boolean checkNotNull(Object reference, String errorMessageTemplate, Object... errorMessageArgs) { return checkNotNullInternal(reference, sStrictMode, errorMessageTemplate, errorMessageArgs); } /** * Ensures that the current thread is the UI thread. */ public static boolean checkUiThread() { return checkUiThreadInternal(sStrictMode, "This method must be called from the UI thread.", EMPTY_ARGUMENTS); } /** * Ensures that the current thread is the UI thread, with an error message. */ public static boolean checkUiThread(String errorMessage) { return checkUiThreadInternal(sStrictMode, errorMessage, EMPTY_ARGUMENTS); } /** * Ensures that the current thread is the UI thread, with an error message that takes * arguments. */ public static boolean checkUiThread(String errorMessageTemplate, Object... errorMessageArgs) { return checkUiThreadInternal(false, errorMessageTemplate, errorMessageArgs); } } private static boolean checkArgumentInternal(boolean expression, boolean allowThrow, String errorMessageTemplate, Object... errorMessageArgs) { if (expression) { return true; } String errorMessage = format(errorMessageTemplate, errorMessageArgs); if (allowThrow) { throw new IllegalArgumentException(errorMessage); } MoPubLog.e(errorMessage); return false; } private static boolean checkStateInternal(boolean expression, boolean allowThrow, String errorMessageTemplate, Object... errorMessageArgs) { if (expression) { return true; } String errorMessage = format(errorMessageTemplate, errorMessageArgs); if (allowThrow) { throw new IllegalStateException(errorMessage); } MoPubLog.e(errorMessage); return false; } private static boolean checkNotNullInternal(Object reference, boolean allowThrow, String errorMessageTemplate, Object... errorMessageArgs) { if (reference != null) { return true; } String errorMessage = format(errorMessageTemplate, errorMessageArgs); if (allowThrow) { throw new NullPointerException(errorMessage); } MoPubLog.e(errorMessage); return false; } private static boolean checkUiThreadInternal(boolean allowThrow, String errorMessageTemplate, Object... errorMessageArgs) { // Check that the main looper is the current looper. if (Looper.getMainLooper().equals(Looper.myLooper())) { return true; } String errorMessage = format(errorMessageTemplate, errorMessageArgs); if (allowThrow) { throw new IllegalStateException(errorMessage); } MoPubLog.e(errorMessage); return false; } /** * Substitutes each {@code %s} in {@code template} with an argument. These are matched by * position - the first {@code %s} gets {@code args[0]}, etc. */ private static String format(String template, Object... args) { template = String.valueOf(template); // null -> "null" try { return String.format(template, args); } catch (IllegalFormatException exception) { MoPubLog.e("MoPub preconditions had a format exception: " + exception.getMessage()); return template; } } }