Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ISBNValidator |
|
| 2.272727272727273;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 | } |