blob: 598365e9ff695784c5ac846821e2a6d43edb9847 [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.sdk.core.util;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.scout.sdk.core.log.FormattingTuple;
import org.eclipse.scout.sdk.core.log.MessageFormatter;
/**
* <h3>{@link Ensure}</h3>
*
* @since 6.1.0
*/
public final class Ensure {
private Ensure() {
}
/**
* Ensures that the given expression is {@code true}. Throws an {@link IllegalArgumentException} otherwise.
*
* @param expression
* The expression to check.
* @throws IllegalArgumentException
* if the given expression is {@code false}.
*/
public static void isTrue(boolean expression) {
isTrue(expression, "The validated expression is false");
}
/**
* Ensures that the given expression is {@code true}. Throws an {@link IllegalArgumentException} otherwise.
*
* @param expression
* The expression to check.
* @param msg
* The message to show if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @throws IllegalArgumentException
* if the given expression is {@code false}.
*/
public static void isTrue(boolean expression, CharSequence msg, Object... msgArgs) {
if (!expression) {
fail(msg, msgArgs);
}
}
/**
* Ensures that the given expression is {@code false}. Throws an {@link IllegalArgumentException} otherwise.
*
* @param expression
* The expression to check.
* @throws IllegalArgumentException
* if the given expression is {@code true}.
*/
public static void isFalse(boolean expression) {
isFalse(expression, "The validated expression is true");
}
/**
* Ensures that the given expression is {@code false}. Throws an {@link IllegalArgumentException} otherwise.
*
* @param expression
* The expression to check.
* @param msg
* The message to show if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @throws IllegalArgumentException
* if the given expression is {@code true}.
*/
public static void isFalse(boolean expression, CharSequence msg, Object... msgArgs) {
isTrue(!expression, msg, msgArgs);
}
/**
* Ensures that the given {@link Path} points to an existing file.
*
* @param candidate
* The {@link Path} to check.
* @return The given {@link Path} if it is a file.
* @throws IllegalArgumentException
* if the given {@link Path} is {@code null} or not a file.
*/
public static Path isFile(Path candidate) {
return isFile(candidate, "'{}' is not a file.", candidate);
}
/**
* Ensures that the given {@link Path} points to an existing file.
*
* @param candidate
* The {@link Path} to check.
* @param msg
* The message to show if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return The given {@link Path} if it is a file.
* @throws IllegalArgumentException
* if the given {@link Path} is {@code null} or not a file.
*/
public static Path isFile(Path candidate, CharSequence msg, Object... msgArgs) {
if (candidate == null || !Files.isReadable(candidate) || !Files.isRegularFile(candidate)) {
fail(msg, msgArgs);
}
return candidate;
}
/**
* Ensures that the given {@link Path} points to an existing directory.
*
* @param candidate
* The {@link Path} to check.
* @return The given {@link Path} if it is a directory.
* @throws IllegalArgumentException
* if the given {@link Path} is {@code null} or not a directory.
*/
public static Path isDirectory(Path candidate) {
return isDirectory(candidate, "'{}' is not a directory.", candidate);
}
/**
* Ensures that the given {@link Path} points to an existing directory.
*
* @param candidate
* The {@link Path} to check.
* @param msg
* The message to show if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return The given {@link Path} if it is a directory.
* @throws IllegalArgumentException
* if the given {@link Path} is {@code null} or not a directory.
*/
public static Path isDirectory(Path candidate, CharSequence msg, Object... msgArgs) {
if (candidate == null || !Files.isReadable(candidate) || !Files.isDirectory(candidate)) {
fail(msg, msgArgs);
}
return candidate;
}
/**
* Ensures that the given object is not {@code null}.<br>
* <br>
* <b>Note:</b><br>
* This method differs to {@link Objects#requireNonNull(Object)} in the way that it does not throw a
* {@link NullPointerException} but an {@link IllegalArgumentException} instead.
*
* @param o
* The object to check.
* @return The given object if it is not {@code null}.
* @throws IllegalArgumentException
* if the object is {@code null}.
*/
public static <T> T notNull(T o) {
return notNull(o, "Object is null");
}
/**
* Ensures that the given object is not {@code null}.<br>
* <br>
* <b>Note:</b><br>
* This method differs to {@link Objects#requireNonNull(Object, String)} in the way that it does not throw a
* {@link NullPointerException} but an {@link IllegalArgumentException} instead.
*
* @param o
* The object to check.
* @param msg
* The message to show if the object is {@code null}.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return The given object if it is not {@code null}.
* @throws IllegalArgumentException
* if the object is {@code null}.
*/
public static <T> T notNull(T o, CharSequence msg, Object... msgArgs) {
if (o == null) {
fail(msg, msgArgs);
}
return o;
}
/**
* Ensures that the given {@link CharSequence} contains visible characters (is not blank) according to
* {@link Strings#isBlank(CharSequence)}.
*
* @param in
* The {@link CharSequence} to check.
* @return The given {@link CharSequence} if it is not blank.
* @throws IllegalArgumentException
* if the given {@link CharSequence} is blank.
*/
public static <T extends CharSequence> T notBlank(T in) {
return notBlank(in, "CharSequence is blank but expected to contain characters.", (Object[]) null);
}
/**
* Ensures that the given {@link CharSequence} contains visible characters (is not blank) according to
* {@link Strings#isBlank(CharSequence)}.
*
* @param in
* The {@link CharSequence} to check.
* @param msg
* The message to show if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return The given {@link CharSequence} if it is not blank.
* @throws IllegalArgumentException
* if the given {@link CharSequence} is blank.
* @see Strings#isBlank(CharSequence)
* @see Strings#notBlank(CharSequence)
*/
public static <T extends CharSequence> T notBlank(T in, CharSequence msg, Object... msgArgs) {
if (Strings.isBlank(in)) {
fail(msg, msgArgs);
}
return in;
}
/**
* Ensures that both parameters are the same instance or are both {@code null}.
*
* @param a
* the value to be tested.
* @param b
* the value to be tested against.
* @throws IllegalArgumentException
* if a is not same as b.
*/
public static void same(Object a, Object b) {
same(a, b, "Values are not the same: [{}, {}].", a, b);
}
/**
* Ensures that both parameters are the same instance or are both {@code null}.
*
* @param a
* the value to be tested.
* @param b
* the value to be tested against.
* @param msg
* message if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @throws IllegalArgumentException
* if a is not same as b.
*/
public static void same(Object a, Object b, CharSequence msg, Object... msgArgs) {
if (a != b) {
fail(msg, msgArgs);
}
}
/**
* Ensures that both parameters have the same value.
*
* @param a
* the value to be tested.
* @param b
* the value to be tested against.
* @return a if it is the same as b
* @throws IllegalArgumentException
* if a is not same as b.
*/
public static int same(int a, int b) {
return sameInt(a, b, "Values are not the same: [{}, {}].", a, b);
}
/**
* Ensures that both parameters have the same value.
*
* @param a
* the value to be tested.
* @param b
* the value to be tested against.
* @param msg
* message if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return a if it is the same as b
* @throws IllegalArgumentException
* if a is not same as b.
*/
public static int same(int a, int b, CharSequence msg, Object... msgArgs) {
return sameInt(a, b, msg, msgArgs);
}
private static int sameInt(int a, int b, CharSequence msg, Object... msgArgs) {
if (a != b) {
fail(msg, msgArgs);
}
return a;
}
/**
* Ensures that the given object is {@code instanceof} the given class.
*
* @param a
* The object to test.
* @param type
* The type to test against.
* @return The given object casted to the given type.
* @throws IllegalArgumentException
* if the object or the type is {@code null} or if the object is not {@code instanceof} the given type.
* @see Class#cast(Object)
* @see MessageFormatter
*/
public static <T> T instanceOf(Object a, Class<T> type) {
return instanceOf(a, type, "Object of type {} is not instanceof {}.", notNull(a).getClass(), type);
}
/**
* Ensures that the given object is {@code instanceof} the given class.
*
* @param a
* The object to test.
* @param type
* The type to test against.
* @param msg
* if the assertion fails.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return The given object casted to the given type.
* @throws IllegalArgumentException
* if the object or the type is {@code null} or if the object is not {@code instanceof} the given type.
* @see Class#cast(Object)
* @see MessageFormatter
*/
public static <T> T instanceOf(Object a, Class<T> type, CharSequence msg, Object... msgArgs) {
if (!notNull(type).isAssignableFrom(notNull(a).getClass())) {
fail(msg, msgArgs);
}
return type.cast(a);
}
/**
* To always throw an {@code IllegalArgumentException}.
*
* @param msg
* the message of the {@link IllegalArgumentException}.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @throws IllegalArgumentException
* on any call to that method.
*/
public static void fail(CharSequence msg, Object... msgArgs) {
throw newFail(msg, msgArgs);
}
/**
* Creates a new failure {@link IllegalArgumentException} with given message and arguments.
* <p>
* This method may be useful to manually throw as shown in the following example:<br>
*
* <pre>
* private int method() {
* if (condition) {
* return value;
* }
* throw newFail("condition not met");
* }
* </pre>
*
* @param msg
* the message of the {@link IllegalArgumentException}.
* @param msgArgs
* The arguments to be placed into the formatting anchors of the given message. See {@link MessageFormatter}.
* @return A new {@link IllegalArgumentException} with given message.
*/
public static IllegalArgumentException newFail(CharSequence msg, Object... msgArgs) {
FormattingTuple tuple = MessageFormatter.arrayFormat(msg, msgArgs);
return new IllegalArgumentException(tuple.message(), tuple.firstThrowable().orElse(null));
}
/**
* Returns a merge function, suitable for use in {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
* {@link Collectors#toMap(Function, Function, BinaryOperator) toMap()}, which always throws
* {@code IllegalArgumentException}.
* <p>
* This can be used to enforce the assumption that the elements being collected are distinct.
*
* @return a merge function which always throw {@code IllegalArgumentException}
*/
public static <T> BinaryOperator<T> failOnDuplicates() {
return (u, v) -> {
throw newFail("Unexpected duplicates found: '{}' and '{}'.", u, v);
};
}
}