Coverage Report - org.apache.commons.validator.routines.ISBNValidator
 
Classes in this File Line Coverage Branch Coverage Complexity
ISBNValidator
100%
35/35
95%
19/20
2.273
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.validator.routines;
 18  
 
 19  
 import java.io.Serializable;
 20  
 import org.apache.commons.validator.routines.checkdigit.EAN13CheckDigit;
 21  
 import org.apache.commons.validator.routines.checkdigit.ISBN10CheckDigit;
 22  
 import org.apache.commons.validator.routines.checkdigit.CheckDigitException;
 23  
 
 24  
 /**
 25  
  * <b>ISBN-10</b> and <b>ISBN-13</b> Code Validation.
 26  
  * <p>
 27  
  * This validator validates the code is either a valid ISBN-10
 28  
  * (using a {@link CodeValidator} with the {@link ISBN10CheckDigit})
 29  
  * or a valid ISBN-13 code (using a {@link CodeValidator} with the
 30  
  * the {@link EAN13CheckDigit} routine).
 31  
  * <p>
 32  
  * The <code>validate()</code> methods return the ISBN code with formatting
 33  
  * characters removed if valid or <code>null</code> if invalid.
 34  
  * <p>
 35  
  * This validator also provides the facility to convert ISBN-10 codes to
 36  
  * ISBN-13 if the <code>convert</code> property is <code>true</code>.
 37  
  * <p>
 38  
  * From 1st January 2007 the book industry will start to use a new 13 digit
 39  
  * ISBN number (rather than this 10 digit ISBN number). ISBN-13 codes are
 40  
  * <a href="http://en.wikipedia.org/wiki/European_Article_Number">EAN</a>
 41  
  * codes, for more information see:</p>
 42  
  *
 43  
  * <ul>
 44  
  *   <li><a href="http://en.wikipedia.org/wiki/ISBN">Wikipedia - International
 45  
  *       Standard Book Number (ISBN)</a>.</li>
 46  
  *   <li>EAN - see
 47  
  *       <a href="http://en.wikipedia.org/wiki/European_Article_Number">Wikipedia -
 48  
  *       European Article Number</a>.</li>
 49  
  *   <li><a href="http://www.isbn.org/standards/home/isbn/transition.asp">ISBN-13
 50  
  *       Transition details</a>.</li>
 51  
  * </ul>
 52  
  *
 53  
  * @version $Revision: 1715435 $
 54  
  * @since Validator 1.4
 55  
  */
 56  
 public class ISBNValidator implements Serializable {
 57  
 
 58  
     private static final int ISBN_10_LEN = 10;
 59  
 
 60  
     private static final long serialVersionUID = 4319515687976420405L;
 61  
 
 62  
     private static final String SEP = "(?:\\-|\\s)";
 63  
     private static final String GROUP = "(\\d{1,5})";
 64  
     private static final String PUBLISHER = "(\\d{1,7})";
 65  
     private static final String TITLE = "(\\d{1,6})";
 66  
 
 67  
     /**
 68  
      * ISBN-10 consists of 4 groups of numbers separated by either dashes (-)
 69  
      * or spaces.  The first group is 1-5 characters, second 1-7, third 1-6,
 70  
      * and fourth is 1 digit or an X.
 71  
      */
 72  
     static final String ISBN10_REGEX     =
 73  
                   "^(?:(\\d{9}[0-9X])|(?:" + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9X])))$";
 74  
 
 75  
     /**
 76  
      * ISBN-13 consists of 5 groups of numbers separated by either dashes (-)
 77  
      * or spaces.  The first group is 978 or 979, the second group is
 78  
      * 1-5 characters, third 1-7, fourth 1-6, and fifth is 1 digit.
 79  
      */
 80  
     static final String ISBN13_REGEX     =
 81  
         "^(978|979)(?:(\\d{10})|(?:" + SEP + GROUP + SEP + PUBLISHER + SEP + TITLE + SEP + "([0-9])))$";
 82  
 
 83  
     /** ISBN Code Validator (which converts ISBN-10 codes to ISBN-13 */
 84  1
     private static final ISBNValidator ISBN_VALIDATOR = new ISBNValidator();
 85  
 
 86  
     /** ISBN Code Validator (which converts ISBN-10 codes to ISBN-13 */
 87  1
     private static final ISBNValidator ISBN_VALIDATOR_NO_CONVERT = new ISBNValidator(false);
 88  
 
 89  
 
 90  
     /** ISBN-10 Code Validator */
 91  2
     private final CodeValidator isbn10Validator = new CodeValidator(ISBN10_REGEX, 10, ISBN10CheckDigit.ISBN10_CHECK_DIGIT);
 92  
 
 93  
     /** ISBN-13 Code Validator */
 94  2
     private final CodeValidator isbn13Validator = new CodeValidator(ISBN13_REGEX, 13, EAN13CheckDigit.EAN13_CHECK_DIGIT);
 95  
 
 96  
     private final boolean convert;
 97  
 
 98  
     /**
 99  
      * Return a singleton instance of the ISBN validator which
 100  
      * converts ISBN-10 codes to ISBN-13.
 101  
      *
 102  
      * @return A singleton instance of the ISBN validator.
 103  
      */
 104  
     public static ISBNValidator getInstance() {
 105  24
         return ISBN_VALIDATOR;
 106  
     }
 107  
 
 108  
     /**
 109  
      * Return a singleton instance of the ISBN validator specifying
 110  
      * whether ISBN-10 codes should be converted to ISBN-13.
 111  
      *
 112  
      * @param convert <code>true</code> if valid ISBN-10 codes
 113  
      * should be converted to ISBN-13 codes or <code>false</code>
 114  
      * if valid ISBN-10 codes should be returned unchanged.
 115  
      * @return A singleton instance of the ISBN validator.
 116  
      */
 117  
     public static ISBNValidator getInstance(boolean convert) {
 118  1
         return (convert ? ISBN_VALIDATOR : ISBN_VALIDATOR_NO_CONVERT);
 119  
     }
 120  
 
 121  
     /**
 122  
      * Construct an ISBN validator which converts ISBN-10 codes
 123  
      * to ISBN-13.
 124  
      */
 125  
     public ISBNValidator() {
 126  1
         this(true);
 127  1
     }
 128  
 
 129  
     /**
 130  
      * Construct an ISBN validator indicating whether
 131  
      * ISBN-10 codes should be converted to ISBN-13.
 132  
      *
 133  
      * @param convert <code>true</code> if valid ISBN-10 codes
 134  
      * should be converted to ISBN-13 codes or <code>false</code>
 135  
      * if valid ISBN-10 codes should be returned unchanged.
 136  
      */
 137  2
     public ISBNValidator(boolean convert) {
 138  2
         this.convert = convert;
 139  2
     }
 140  
 
 141  
     /**
 142  
      * Check the code is either a valid ISBN-10 or ISBN-13 code.
 143  
      *
 144  
      * @param code The code to validate.
 145  
      * @return <code>true</code> if a valid ISBN-10 or
 146  
      * ISBN-13 code, otherwise <code>false</code>.
 147  
      */
 148  
     public boolean isValid(String code) {
 149  34
         return (isValidISBN13(code) || isValidISBN10(code));
 150  
     }
 151  
 
 152  
     /**
 153  
      * Check the code is a valid ISBN-10 code.
 154  
      *
 155  
      * @param code The code to validate.
 156  
      * @return <code>true</code> if a valid ISBN-10
 157  
      * code, otherwise <code>false</code>.
 158  
      */
 159  
     public boolean isValidISBN10(String code) {
 160  69
         return isbn10Validator.isValid(code);
 161  
     }
 162  
 
 163  
     /**
 164  
      * Check the code is a valid ISBN-13 code.
 165  
      *
 166  
      * @param code The code to validate.
 167  
      * @return <code>true</code> if a valid ISBN-13
 168  
      * code, otherwise <code>false</code>.
 169  
      */
 170  
     public boolean isValidISBN13(String code) {
 171  62
         return isbn13Validator.isValid(code);
 172  
     }
 173  
 
 174  
     /**
 175  
      * Check the code is either a valid ISBN-10 or ISBN-13 code.
 176  
      * <p>
 177  
      * If valid, this method returns the ISBN code with
 178  
      * formatting characters removed (i.e. space or hyphen).
 179  
      * <p>
 180  
      * Converts an ISBN-10 codes to ISBN-13 if
 181  
      * <code>convertToISBN13</code> is <code>true</code>.
 182  
      *
 183  
      * @param code The code to validate.
 184  
      * @return A valid ISBN code if valid, otherwise <code>null</code>.
 185  
      */
 186  
     public String validate(String code) {
 187  19
         String result = validateISBN13(code);
 188  19
         if (result == null) {
 189  13
             result = validateISBN10(code);
 190  13
             if (result != null && convert) {
 191  6
                 result = convertToISBN13(result);
 192  
             }
 193  
         }
 194  19
         return result;
 195  
     }
 196  
 
 197  
     /**
 198  
      * Check the code is a valid ISBN-10 code.
 199  
      * <p>
 200  
      * If valid, this method returns the ISBN-10 code with
 201  
      * formatting characters removed (i.e. space or hyphen).
 202  
      *
 203  
      * @param code The code to validate.
 204  
      * @return A valid ISBN-10 code if valid,
 205  
      * otherwise <code>null</code>.
 206  
      */
 207  
     public String validateISBN10(String code) {
 208  40
         Object result = isbn10Validator.validate(code);
 209  40
         return (result == null ? null : result.toString());
 210  
     }
 211  
 
 212  
     /**
 213  
      * Check the code is a valid ISBN-13 code.
 214  
      * <p>
 215  
      * If valid, this method returns the ISBN-13 code with
 216  
      * formatting characters removed (i.e. space or hyphen).
 217  
      *
 218  
      * @param code The code to validate.
 219  
      * @return A valid ISBN-13 code if valid,
 220  
      * otherwise <code>null</code>.
 221  
      */
 222  
     public String validateISBN13(String code) {
 223  47
         Object result = isbn13Validator.validate(code);
 224  47
         return (result == null ? null : result.toString());
 225  
     }
 226  
 
 227  
     /**
 228  
      * Convert an ISBN-10 code to an ISBN-13 code.
 229  
      * <p>
 230  
      * This method requires a valid ISBN-10 with NO formatting
 231  
      * characters.
 232  
      *
 233  
      * @param isbn10 The ISBN-10 code to convert
 234  
      * @return A converted ISBN-13 code or <code>null</code>
 235  
      * if the ISBN-10 code is not valid
 236  
      */
 237  
     public String convertToISBN13(String isbn10) {
 238  
 
 239  11
         if (isbn10 == null) {
 240  1
             return null;
 241  
         }
 242  
 
 243  10
         String input = isbn10.trim();
 244  10
         if (input.length() != ISBN_10_LEN) {
 245  3
             throw new IllegalArgumentException("Invalid length " + input.length() + " for '" + input + "'");
 246  
         }
 247  
 
 248  
         // Calculate the new ISBN-13 code (drop the original checkdigit)
 249  7
         String isbn13 = "978" + input.substring(0, ISBN_10_LEN - 1);
 250  
         try {
 251  7
             String checkDigit = isbn13Validator.getCheckDigit().calculate(isbn13);
 252  6
             isbn13 += checkDigit;
 253  6
             return isbn13;
 254  1
         } catch (CheckDigitException e) {
 255  1
             throw new IllegalArgumentException("Check digit error for '" + input + "' - " + e.getMessage());
 256  
         }
 257  
 
 258  
     }
 259  
 
 260  
 }