All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.validator.internal.constraintvalidators.hv.ISBNValidator Maven / Gradle / Ivy

There is a newer version: 8.0.1.Final
Show newest version
/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or .
 */
package org.hibernate.validator.internal.constraintvalidators.hv;

import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.hibernate.validator.constraints.ISBN;
import org.hibernate.validator.internal.util.Contracts;

/**
 * Checks that a given character sequence (e.g. string) is a valid ISBN.
 *
 * @author Marko Bekhta
 */
public class ISBNValidator implements ConstraintValidator {

	/**
	 * Pattern to replace all non ISBN characters. ISBN can have digits or 'X'.
	 */
	private static Pattern NOT_DIGITS_OR_NOT_X = Pattern.compile( "[^\\dX]" );

	private ISBNValidationAlgorithm isbnValidationAlgorithm;

	@Override
	public void initialize(ISBN constraintAnnotation) {
		this.isbnValidationAlgorithm = ISBNValidationAlgorithm.from( constraintAnnotation.type() );
	}

	@Override
	public boolean isValid(CharSequence isbn, ConstraintValidatorContext context) {
		if ( isbn == null ) {
			return true;
		}

		// Replace all non-digit (or !=X) chars
		String digits = NOT_DIGITS_OR_NOT_X.matcher( isbn ).replaceAll( "" );

		// Check if the length of resulting string matches the expecting one
		if ( !isbnValidationAlgorithm.isValidLength( digits.length() ) ) {
			return false;
		}

		return isbnValidationAlgorithm.isValidChecksum( digits );
	}

	private interface ISBNValidationAlgorithm {
		boolean isValidLength(int length);

		boolean isValidChecksum(String isbn);

		static ISBNValidationAlgorithmImpl from(ISBN.Type type) {
			Contracts.assertNotNull( type );
			switch ( type ) {
				case ISBN_10:
					return ISBNValidationAlgorithmImpl.ISBN_10;
				case ISBN_13:
					return ISBNValidationAlgorithmImpl.ISBN_13;
				case ANY:
				default:
					return ISBNValidationAlgorithmImpl.ANY;
			}
		}
	}

	private enum ISBNValidationAlgorithmImpl implements ISBNValidationAlgorithm {

		ISBN_10 {
			@Override
			public boolean isValidChecksum(String isbn) {
				return checkChecksumISBN10( isbn );
			}

			@Override
			public boolean isValidLength(int length) {
				return 10 == length;
			}
		},
		ISBN_13 {
			@Override
			public boolean isValidChecksum(String isbn) {
				return checkChecksumISBN13( isbn );
			}

			@Override
			public boolean isValidLength(int length) {
				return 13 == length;
			}
		},
		ANY {
			@Override
			public boolean isValidLength(int length) {
				return 10 == length || 13 == length;
			}

			@Override
			public boolean isValidChecksum(String isbn) {
				int length = isbn.length();
				if ( length == 10 ) {
					return checkChecksumISBN10( isbn );
				}
				else if ( length == 13 ) {
					return checkChecksumISBN13( isbn );
				}
				throw new IllegalStateException( "Invalid/unsupported isbn value length" );
			}
		};

		/**
		 * Check the digits for ISBN 10 using algorithm from
		 * Wikipedia.
		 */
		private static boolean checkChecksumISBN10(String isbn) {
			int sum = 0;
			for ( int i = 0; i < isbn.length() - 1; i++ ) {
				sum += ( isbn.charAt( i ) - '0' ) * ( 10 - i );
			}
			sum += isbn.charAt( 9 ) == 'X' ? 10 : isbn.charAt( 9 ) - '0';

			return ( sum % 11 ) == 0;
		}

		/**
		 * Check the digits for ISBN 13 using algorithm from
		 * Wikipedia.
		 */
		private static boolean checkChecksumISBN13(String isbn) {
			int sum = 0;
			for ( int i = 0; i < isbn.length(); i++ ) {
				sum += ( isbn.charAt( i ) - '0' ) * ( i % 2 == 0 ? 1 : 3 );
			}

			return ( sum % 10 ) == 0;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy