[ISSUE-3007][Improve] Introduce a utils to process conditions check and exceptions thrown for console-service module. (#3652)

Co-authored-by: zhengkezhou <36791902+zzzk1@users.noreply.github.com>
diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Throws.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Throws.java
new file mode 100644
index 0000000..8fce0e7
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/base/util/Throws.java
@@ -0,0 +1,199 @@
+/*
+ * 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.streampark.console.base.util;
+
+import org.apache.streampark.common.util.AssertUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+
+import javax.annotation.Nonnull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.TimeUnit;
+
+import scala.Tuple2;
+
+/** The util to throw a sub-exception of {@link RuntimeException} for the specified condition. */
+public class Throws {
+
+  private static final Cache<Tuple2<Class<?>, Class<?>>, Constructor<?>> CACHE =
+      Caffeine.newBuilder().expireAfterAccess(1, TimeUnit.DAYS).maximumSize(32).build();
+
+  private Throws() {}
+
+  /**
+   * Throw a runtime exception to the specified class type and condition.
+   *
+   * @param bool The condition.
+   * @param exceptionClass The target runtime exception class type.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfTrue(
+      boolean bool, @Nonnull Class<T> exceptionClass) {
+    if (bool) {
+      throw createRuntimeException(exceptionClass);
+    }
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and condition.
+   *
+   * @param bool The condition.
+   * @param exceptionClass The target runtime exception class type.
+   * @param msgFormat The error message or message format.
+   * @param args The real value of placeholders.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfTrue(
+      boolean bool, @Nonnull Class<T> exceptionClass, String msgFormat, Object... args) {
+    if (bool) {
+      throw createRuntimeException(exceptionClass, getErrorMsg(msgFormat, args));
+    }
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and condition.
+   *
+   * @param bool The condition.
+   * @param exceptionClass The target runtime exception class type.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfFalse(
+      boolean bool, @Nonnull Class<T> exceptionClass) {
+    throwIfTrue(!bool, exceptionClass);
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and condition.
+   *
+   * @param bool The condition.
+   * @param exceptionClass The target runtime exception class type.
+   * @param msgFormat The error message or message format.
+   * @param args The real value of placeholders.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfFalse(
+      boolean bool, @Nonnull Class<T> exceptionClass, String msgFormat, Object... args) {
+    throwIfTrue(!bool, exceptionClass, msgFormat, args);
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and object.
+   *
+   * @param obj The object.
+   * @param exceptionClass The target runtime exception class type.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfNull(
+      Object obj, @Nonnull Class<T> exceptionClass) {
+    throwIfTrue(obj == null, exceptionClass);
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and object.
+   *
+   * @param obj The object.
+   * @param exceptionClass The target runtime exception class type.
+   * @param msgFormat The error message or message format.
+   * @param args The real value of placeholders.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfNull(
+      Object obj, @Nonnull Class<T> exceptionClass, String msgFormat, Object... args) {
+    throwIfTrue(obj == null, exceptionClass, msgFormat, args);
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and object.
+   *
+   * @param obj The object.
+   * @param exceptionClass The target runtime exception class type.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfNonnull(
+      Object obj, @Nonnull Class<T> exceptionClass) {
+    throwIfTrue(obj != null, exceptionClass);
+  }
+
+  /**
+   * Throw a runtime exception to the specified class type and object.
+   *
+   * @param obj The object.
+   * @param exceptionClass The target runtime exception class type.
+   * @param msgFormat The error message or message format.
+   * @param args The real value of placeholders.
+   * @param <T> The target exception class.
+   */
+  public static <T extends RuntimeException> void throwIfNonnull(
+      Object obj, @Nonnull Class<T> exceptionClass, String msgFormat, Object... args) {
+    throwIfTrue(obj != null, exceptionClass, msgFormat, args);
+  }
+
+  private static <T extends RuntimeException> T createRuntimeException(
+      @Nonnull Class<T> exceptionClass, String... errorMsgs) {
+    try {
+      return createRuntimeExceptionInternal(exceptionClass, errorMsgs);
+    } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static <T extends RuntimeException> T createRuntimeExceptionInternal(
+      @Nonnull Class<T> exceptionClass, String... errorMsgs)
+      throws InvocationTargetException, InstantiationException, IllegalAccessException {
+    AssertUtils.notNull(exceptionClass, "The target exception must be specified.");
+    Tuple2<Class<?>, Class<?>> key =
+        new Tuple2<>(exceptionClass, hasElements(errorMsgs) ? String.class : null);
+    Constructor<?> constructor =
+        CACHE.get(
+            key,
+            classAndParams -> {
+              try {
+                return hasElements(errorMsgs)
+                    ? exceptionClass.getConstructor(String.class)
+                    : exceptionClass.getConstructor();
+              } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+              }
+            });
+    AssertUtils.notNull(
+        constructor,
+        String.format("There's no a constructor for exception '%s'.", exceptionClass.getName()));
+    return hasElements(errorMsgs)
+        ? (T) constructor.newInstance(errorMsgs[0])
+        : (T) constructor.newInstance();
+  }
+
+  private static boolean hasElements(Object[] objects) {
+    return objects != null && objects.length > 0;
+  }
+
+  private static String getErrorMsg(String msgFormat, Object... args) {
+    if (StringUtils.isBlank(msgFormat)) {
+      return msgFormat;
+    }
+    if (args == null || args.length < 1) {
+      return msgFormat;
+    }
+    return String.format(msgFormat, args);
+  }
+}
diff --git a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/utils/ThrowsTest.java b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/utils/ThrowsTest.java
new file mode 100644
index 0000000..ae2201a
--- /dev/null
+++ b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/utils/ThrowsTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.streampark.console.core.utils;
+
+import org.apache.streampark.console.base.exception.AlertException;
+import org.apache.streampark.console.base.util.Throws;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class ThrowsTest {
+
+  static final String PURE_MSG_TPL = "Pure test string.";
+  static final String MSG_TPL = "Template string %s.";
+  static final String ARG = "Hello";
+  static final String RENDERED_STR = String.format(MSG_TPL, ARG);
+
+  public static class TestRuntimeException extends RuntimeException {
+    public TestRuntimeException() {}
+  }
+
+  @Test
+  void testThrowIfTrue() {
+    assertThatThrownBy(() -> Throws.throwIfTrue(true, null))
+        .hasMessage("The target exception must be specified.");
+    assertThatThrownBy(() -> Throws.throwIfTrue(true, AlertException.class))
+        .hasCauseInstanceOf(NoSuchMethodException.class);
+    assertThatThrownBy(() -> Throws.throwIfTrue(true, AlertException.class, PURE_MSG_TPL))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(PURE_MSG_TPL);
+    assertThatThrownBy(() -> Throws.throwIfTrue(true, AlertException.class, MSG_TPL, ARG))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(RENDERED_STR);
+    assertThatThrownBy(() -> Throws.throwIfTrue(true, TestRuntimeException.class))
+        .isInstanceOf(TestRuntimeException.class);
+
+    Throws.throwIfTrue(false, null);
+    Throws.throwIfTrue(false, AlertException.class);
+    Throws.throwIfTrue(false, AlertException.class, PURE_MSG_TPL);
+    Throws.throwIfTrue(false, AlertException.class, MSG_TPL, ARG);
+    Throws.throwIfTrue(false, TestRuntimeException.class);
+  }
+
+  @Test
+  void testThrowIfFalse() {
+    assertThatThrownBy(() -> Throws.throwIfFalse(false, null))
+        .hasMessage("The target exception must be specified.");
+    assertThatThrownBy(() -> Throws.throwIfFalse(false, AlertException.class))
+        .hasCauseInstanceOf(NoSuchMethodException.class);
+    assertThatThrownBy(() -> Throws.throwIfFalse(false, AlertException.class, PURE_MSG_TPL))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(PURE_MSG_TPL);
+    assertThatThrownBy(() -> Throws.throwIfFalse(false, AlertException.class, MSG_TPL, ARG))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(RENDERED_STR);
+    assertThatThrownBy(() -> Throws.throwIfFalse(false, TestRuntimeException.class))
+        .isInstanceOf(TestRuntimeException.class);
+
+    Throws.throwIfFalse(true, null);
+    Throws.throwIfFalse(true, AlertException.class);
+    Throws.throwIfFalse(true, AlertException.class, PURE_MSG_TPL);
+    Throws.throwIfFalse(true, AlertException.class, MSG_TPL, ARG);
+    Throws.throwIfFalse(true, TestRuntimeException.class);
+  }
+
+  @Test
+  void testThrowIfNull() {
+    assertThatThrownBy(() -> Throws.throwIfNull(null, null))
+        .hasMessage("The target exception must be specified.");
+    assertThatThrownBy(() -> Throws.throwIfNull(null, AlertException.class))
+        .hasCauseInstanceOf(NoSuchMethodException.class);
+    assertThatThrownBy(() -> Throws.throwIfNull(null, AlertException.class, PURE_MSG_TPL))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(PURE_MSG_TPL);
+    assertThatThrownBy(() -> Throws.throwIfNull(null, AlertException.class, MSG_TPL, ARG))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(RENDERED_STR);
+    assertThatThrownBy(() -> Throws.throwIfNull(null, TestRuntimeException.class))
+        .isInstanceOf(TestRuntimeException.class);
+
+    Throws.throwIfNull(this, null);
+    Throws.throwIfNull(this, AlertException.class);
+    Throws.throwIfNull(this, AlertException.class, PURE_MSG_TPL);
+    Throws.throwIfNull(this, AlertException.class, MSG_TPL, ARG);
+    Throws.throwIfNull(this, TestRuntimeException.class);
+  }
+
+  @Test
+  void testThrowIfNonnull() {
+    assertThatThrownBy(() -> Throws.throwIfNonnull(this, null))
+        .hasMessage("The target exception must be specified.");
+    assertThatThrownBy(() -> Throws.throwIfNonnull(this, AlertException.class))
+        .hasCauseInstanceOf(NoSuchMethodException.class);
+    assertThatThrownBy(() -> Throws.throwIfNonnull(this, AlertException.class, PURE_MSG_TPL))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(PURE_MSG_TPL);
+    assertThatThrownBy(() -> Throws.throwIfNonnull(this, AlertException.class, MSG_TPL, ARG))
+        .isInstanceOf(AlertException.class)
+        .hasMessage(RENDERED_STR);
+    assertThatThrownBy(() -> Throws.throwIfNonnull(this, TestRuntimeException.class))
+        .isInstanceOf(TestRuntimeException.class);
+
+    Throws.throwIfNonnull(null, null);
+    Throws.throwIfNonnull(null, AlertException.class);
+    Throws.throwIfNonnull(null, AlertException.class, PURE_MSG_TPL);
+    Throws.throwIfNonnull(null, AlertException.class, MSG_TPL, ARG);
+    Throws.throwIfNonnull(null, TestRuntimeException.class);
+  }
+}