/* * Copyright (c) 2009-2015 * IT-Consulting Stephan Schloepke (http://www.schloepke.de/) * klemm software consulting Mirko Klemm (http://www.klemm-scs.com/) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jbasics.checker; import org.jbasics.annotation.ImmutableState; import org.jbasics.annotation.ThreadSafe; import org.jbasics.pattern.delegation.Delegate; import org.jbasics.types.sequences.Sequence; import org.jbasics.types.tuples.Range; import java.util.Collection; import java.util.Map; import java.util.regex.Pattern; /** * Simple class offering methods to check if a call contract is broken or not. <p> Usually one makes a check of null and * throws an {@link IllegalAccessException} or a {@link NullPointerException}. This is a line of code written * constantly. This helper is supposed to limit the code to write especially in constructors or setter methods. </p> <p> * Example: </p> * <pre> * public void setSomething(Object something) { * if (something == null) { * throw new {@link IllegalArgumentException}("Null parameter: something"); * } * this.something = something; * } * </pre> * <p> Would change to: </p> * <pre> * public void setSomething(Object something) { * this.something = {@link ContractCheck#mustNotBeNull(Object, String)}(something, "something"); * } * </pre> * <p> All check methods throw a {@link ContractViolationException} if the check fails. </p> * * @author Stephan Schloepke * @since 1.0 */ @ThreadSafe @ImmutableState @SuppressWarnings("nls") public final class ContractCheck { private static final String UNKNOWN = "?"; /** * Checks if the given instance is not null * * @param <T> The type of instance to check * @param instanceName The name of the instance (should not be null). * @param instance The instance to check. * * @return The checked instance which is guaranteed to not be null. * * @throws ContractViolationException If the instance to check is null. * @since 1.0 */ public static <T> T mustNotBeNull(final T instance, final String instanceName) { if (instance == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } return instance; } /** * Checks if the given delegated instance is not null (neither the delegate nor the call to delegate() must be null) * * @param <T> The type of the delegated instance to check * @param instanceName The name of the delegated instance (should not be null). * @param delegatedInstance The delegate instance to check. * * @return The checked instance which is guaranteed to not be null. * * @throws ContractViolationException If the delage instance to check is null or the delegated value is null. * @since 1.0 */ public static <T> T mustNotBeDelegatedNull(final Delegate<T> delegatedInstance, final String instanceName) { T instance; if (delegatedInstance == null || (instance = delegatedInstance.delegate()) == null) { throw ContractCheck.createNotNullException("mustNotBeNullDelegate", instanceName); } return instance; } /** * Creates a {@link ContractViolationException} and removes all parts of the {@link ContractCheck} class from the * stack trace. * * @param instanceName * * @return */ private static ContractViolationException createNotNullException(final String messageKey, final String instanceName, final Object... extra) { final ContractViolationException temp = new ContractViolationException(messageKey, instanceName != null ? instanceName : ContractCheck.UNKNOWN); final StackTraceElement[] tempStack = temp.getStackTrace(); int i = 0; while (i < tempStack.length && tempStack[i].getClassName().equals(ContractCheck.class.getName())) { i++; } if (i > 0 && i < tempStack.length) { final StackTraceElement[] tempNewStack = new StackTraceElement[tempStack.length - i]; System.arraycopy(tempStack, i, tempNewStack, 0, tempNewStack.length); temp.setStackTrace(tempNewStack); } return temp; } /** * Checks the supplied instance collection to be not null and not zero length. * * @param <T> The type of the instance * @param collection The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static <T> Collection<T> mustNotBeNullOrEmpty(final Collection<T> collection, final String instanceName) { if (collection == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (collection.size() == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return collection; } /** * Checks the supplied instance collection to be not null and not zero length. * * @param <T> The type of the instance * @param sequence The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static <T> Sequence<T> mustNotBeNullOrEmpty(final Sequence<T> sequence, final String instanceName) { if (sequence == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (sequence.size() == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return sequence; } /** * Checks the supplied instance map to be not null and not zero length. * * @param <K> The type of the map key * @param <V> The type of the map value * @param map The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static <K, V> Map<K, V> mustNotBeNullOrEmpty(final Map<K, V> map, final String instanceName) { if (map == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (map.size() == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return map; } /** * Checks the supplied instance array to be not null and not zero length. * * @param <T> The type of the instance * @param array The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static <T> T[] mustNotBeNullOrEmpty(final T[] array, final String instanceName) { if (array == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (array.length == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return array; } /** * Checks the supplied instance array to be not null and not zero length. * * @param <T> The type of the instance * @param charSequence The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static <T extends CharSequence> T mustNotBeNullOrEmpty(final T charSequence, final String instanceName) { if (charSequence == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (charSequence.length() == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return charSequence; } /** * Checks if the supplied instance is neither null and not empty after the sequence is trimmed. Returns the trimmed * instance. * * @param charSequence The instance to check and trim * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance which is guaranteed to be not null, trimmed and not empty. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static String mustNotBeNullOrTrimmedEmpty(final CharSequence charSequence, final String instanceName) { if (charSequence == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } final String temp = charSequence.toString().trim(); if (temp.length() == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return temp; } /** * Checks the supplied instance array to be not null and not zero length. * * @param byteArray The instance to check * @param instanceName The name of the instance (can be null) for the exception message generated * * @return The checked instance array which is guaranteed to be neither null nor zero length. * * @throws ContractViolationException If the array instance to check is null or zero length. * @since 1.0 */ public static byte[] mustNotBeNullOrEmpty(final byte[] byteArray, final String instanceName) { if (byteArray == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (byteArray.length == 0) { throw new ContractViolationException("mustNotBeEmpty", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } return byteArray; } /** * Checks if the value is in the range of low and high. * * @param intValue The value to check * @param low The inclusive lower bound which is a valid value. * @param high The inclusive upper bound which is a valid value. * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static int mustBeInRange(final int intValue, final int low, final int high, final String instanceName) { if (intValue < low || intValue > high) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, Integer.valueOf(low), Integer.valueOf(high)); } return intValue; } /** * Checks if the value is in the range of low and high. * * @param longValue The value to check * @param low The inclusive lower bound which is a valid value. * @param high The inclusive upper bound which is a valid value. * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static long mustBeInRange(final long longValue, final long low, final long high, final String instanceName) { if (longValue < low || longValue > high) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, Long.valueOf(low), Long.valueOf(high)); } return longValue; } /** * Checks if the value is in the range of low and high. * * @param doubleValue The value to check * @param low The inclusive lower bound which is a valid value. * @param high The inclusive upper bound which is a valid value. * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static double mustBeInRange(final double doubleValue, final double low, final double high, final String instanceName) { if (doubleValue < low || doubleValue > high) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, Double.valueOf(low), Double.valueOf(high)); } return doubleValue; } /** * Checks if the value is not null and in the range of low and high and converts any number to long. * * @param numberValue The value to check * @param low The inclusive lower bound which is a valid value. * @param high The inclusive upper bound which is a valid value. * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static long mustNotBeNullAndInRange(final Number numberValue, final long low, final long high, final String instanceName) { if (numberValue == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } final long longValue = numberValue.longValue(); if (longValue < low || longValue > high) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, Long.valueOf(low), Long.valueOf(high)); } return longValue; } /** * Checks if the value is not null and in the range of low and high and converts any number to double. * * @param numberValue The value to check * @param low The inclusive lower bound which is a valid value. * @param high The inclusive upper bound which is a valid value. * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] and not null * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static double mustNotBeNullAndInRange(final Number numberValue, final double low, final double high, final String instanceName) { if (numberValue == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } final double longValue = numberValue.doubleValue(); if (longValue < low || longValue > high) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, Double.valueOf(low), Double.valueOf(high)); } return longValue; } /** * Checks if the value is in the range of low and high. * * @param <T> The type of the {@link Number} to check * @param <C> The type for the lower and upper bound which is a {@link Comparable} of the type T * @param numberValue The value to check * @param low The inclusive lower bound which is a valid value (or null if open lower bound) * @param high The inclusive upper bound which is a valid value (or null if open upper bound) * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static <T extends Number, C extends Comparable<T>> T mustBeInRange(final T numberValue, final C low, final C high, final String instanceName) { if (numberValue == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (low != null && low.compareTo(numberValue) > 0 || high != null && high.compareTo(numberValue) < 0) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, low, high); } return numberValue; } /** * Checks if the value is in the range of low and high. * * @param <T> The type of the {@link Comparable} to check * @param numberValue The value to check * @param range The range to check with (if null no check is applied other than the null check) * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the given range * * @throws ContractViolationException If the value is not in the given range. * @since 1.0 */ public static <T extends Comparable<T>> T mustBeInRange(final T numberValue, final Range<T> range, final String instanceName) { if (numberValue == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (range != null && !range.isInRange(numberValue)) { throw new ContractViolationException("mustBeInRangeForRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, range); } return numberValue; } /** * Checks if the value is in the range of low and high or is null. * * @param <T> The type of the {@link Number} to check * @param <C> The type for the lower and upper bound which is a {@link Comparable} of the type T * @param numberValue The value to check * @param low The inclusive lower bound which is a valid value (or null if open lower bound) * @param high The inclusive upper bound which is a valid value (or null if open upper bound) * @param instanceName The name of the instance for the exception message (can be null). * * @return The value guaranteed to be within the range [low, high] * * @throws ContractViolationException If the value is not in the range [low, high]. * @since 1.0 */ public static <T extends Number, C extends Comparable<T>> T mustBeInRangeOrNull(final T numberValue, final C low, final C high, final String instanceName) { if (numberValue == null) { return numberValue; } if (low != null && low.compareTo(numberValue) > 0 || high != null && high.compareTo(numberValue) < 0) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, low, high); } return numberValue; } /** * Checks that the given {@link CharSequence} is either null or not null and matches the given pattern (if pattern * is not null). * * @param <T> The type to check derived from {@link CharSequence} * @param charSequence The sequence to check * @param pattern The pattern to check (if null no pattern checking is applied) * @param instanceName The name of the instance as used in the violation exception (if null ? is used) * * @return The {@link CharSequence} guaranteed to be either null or complies to the given pattern * * @throws ContractViolationException If the {@link CharSequence} is not null and does not match the pattern */ public static <T extends CharSequence> T mustMatchPatternOrBeNull(final T charSequence, final Pattern pattern, final String instanceName) { if (charSequence == null) { return null; } if (pattern != null && !pattern.matcher(charSequence).matches()) { throw new ContractViolationException("mustMatchPattern", instanceName != null ? instanceName : ContractCheck.UNKNOWN, pattern.pattern()); } return charSequence; } /** * Checks that the given {@link CharSequence} is not null and matches the given pattern (if pattern is not null). * * @param <T> The type to check derived from {@link CharSequence} * @param charSequence The sequence to check * @param pattern The pattern to check (if null no pattern checking is applied) * @param instanceName The name of the instance as used in the violation exception (if null ? is used) * * @return The {@link CharSequence} guaranteed to be not null and complies to the given pattern * * @throws ContractViolationException If the {@link CharSequence} is null or does not match the pattern * @since 1.0 */ public static <T extends CharSequence> T mustMatchPattern(final T charSequence, final Pattern pattern, final String instanceName) { if (charSequence == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } if (pattern != null && !pattern.matcher(charSequence).matches()) { throw new ContractViolationException("mustMatchPattern", instanceName != null ? instanceName : ContractCheck.UNKNOWN, pattern.pattern()); } return charSequence; } /** * Checks if the given instance is equal to the given check instance. If the check instance is null the instance * must also be null. If the check instance is not null the instance must not be null and must be equal to the check * instance by applying check.equals(instance). Throws an exception when the check is not valid. * * @param <T> The type of the instance * @param instance The instance to check * @param check The instance to compare with * @param instanceName The name of the instance for the exception. * * @return The instance as given * * @throws ContractViolationException If the instance is not equal to the check. * @since 1.0 */ public static <T> T mustBeEqual(final T instance, final T check, final String instanceName) { if (instance == null) { if (check != null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } } else if (check == null) { throw new ContractViolationException("mustBeNull", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } else if (!check.equals(instance)) { throw new ContractViolationException("mustBeEqualTo", instanceName != null ? instanceName : ContractCheck.UNKNOWN, check); } return instance; } /** * Checks if the two given arrays are of same size or both null. If the check is null than instance must be null. If * the check is not null than instance must not be null and be the same size as check. Returns the instance array if * all checks are valid and the caller has the guarantee that the size is equal. * * @param <T> The type of the array instance * @param instance The array instance to check * @param check The array instance to compare the size with * @param instanceName The name of the array instance for the exception. * * @return The array instance as given * * @throws ContractViolationException If the array instance is not the same size as the check instance or both * null. * @since 1.0 */ @SuppressWarnings("boxing") public static <T> T[] mustMatchSizeOrBothBeNull(final T[] instance, final Object[] check, final String instanceName) { if (instance == null) { if (check != null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } } else if (check == null) { throw new ContractViolationException("mustBeNull", instanceName != null ? instanceName : ContractCheck.UNKNOWN); } else if (instance.length != check.length) { throw new ContractViolationException("mustBeOfSize", instanceName != null ? instanceName : ContractCheck.UNKNOWN, check.length, instance.length); } return instance; } /** * Checks if the given array is not null and of the given check size. If the instance array is not null and also the * length of the array is of the cheked size the given array is returned and guaranteed to match the check. * * @param <T> The type of the array instance * @param instance The array instance to check * @param check The size the array needs to have * @param instanceName The name of the array instance for the exception. * * @return The array instance as given * * @throws ContractViolationException If the array instance is null or not the same size as the check size. * @since 1.0 */ @SuppressWarnings("boxing") public static <T> T[] mustMatchSizeAndNotBeNull(final T[] instance, final int check, final String instanceName) { if (instance == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } else if (instance.length != check) { throw new ContractViolationException("mustBeOfSize", instanceName != null ? instanceName : ContractCheck.UNKNOWN, check, instance.length); } return instance; } /** * Checks if the given array is not null and of the given check size. If the instance array is not null and also the * length of the array is of the cheked size the given array is returned and guaranteed to match the check. * * @param <T> The type of the array instance * @param instance The array instance to check * @param minLength The minimum size (included) * @param maxLength The maximum size (included) * @param instanceName The name of the array instance for the exception. * * @return The array instance as given * * @throws ContractViolationException If the array instance is null or not the same size as the check size. * @since 1.0 */ @SuppressWarnings("boxing") public static <T> T[] mustMatchSizeRangeAndNotBeNull(final T[] instance, final int minLength, final int maxLength, final String instanceName) { if (instance == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } else if (instance.length < minLength || instance.length > maxLength) { throw new ContractViolationException("mustBeInRange", instanceName != null ? instanceName : ContractCheck.UNKNOWN, minLength, maxLength); } return instance; } /** * Checks if the given collection is not null and of the given check size. If the instance collection is not null * and also the size of the collection is of the checked size the given collection is returned and guaranteed to * match the check. * * @param <T> The type of the collection instance * @param instance The collection instance to check * @param check The size the collection needs to have * @param instanceName The name of the collection instance for the exception. * * @return The collection instance as given * * @throws ContractViolationException If the collection instance is null or not the same size as the check size. * @since 1.0 */ @SuppressWarnings("boxing") public static <T extends Collection<?>> T mustMatchSizeAndNotBeNull(final T instance, final int check, final String instanceName) { if (instance == null) { throw ContractCheck.createNotNullException("mustNotBeNull", instanceName); } else if (instance.size() != check) { throw new ContractViolationException("mustBeOfSize", instanceName != null ? instanceName : ContractCheck.UNKNOWN, check, instance.size()); } return instance; } /** * Checks if the given boolean expression result is <code>true</code> and otherwise throws a {@link * ContractViolationException}. * * @param expression The result of the boolean expression * @param expressioName The name of the expression * * @since 1.0 */ public static void mustEvalToTrue(final boolean expression, final String expressioName) { if (!expression) { throw new ContractViolationException("mustBeTrue", expressioName != null ? expressioName : ContractCheck.UNKNOWN); } } /** * Checks if the given boolean expression result is <code>false</code> and otherwise throws a {@link * ContractViolationException}. * * @param expression The result of the boolean expression * @param expressioName The name of the expression * * @since 1.0 */ public static void mustEvalToFalse(final boolean expression, final String expressioName) { if (expression) { throw new ContractViolationException("mustBeTrue", expressioName != null ? expressioName : ContractCheck.UNKNOWN); } } }