ISINValidator.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.validator.routines;
- import java.io.Serializable;
- import java.util.Arrays;
- import java.util.Locale;
- import org.apache.commons.validator.routines.checkdigit.ISINCheckDigit;
- /**
- * <b>ISIN</b> (International Securities Identifying Number) validation.
- *
- * <p>
- * ISIN Numbers are 12 character alphanumeric codes used to identify Securities.
- * </p>
- *
- * <p>
- * ISINs consist of two alphabetic characters,
- * which are the ISO 3166-1 alpha-2 code for the issuing country,
- * nine alpha-numeric characters (the National Securities Identifying Number, or NSIN, which identifies the security),
- * and one numerical check digit.
- * They are 12 characters in length.
- * </p>
- *
- * <p>
- * See <a href="https://en.wikipedia.org/wiki/ISIN">Wikipedia - ISIN</a>
- * for more details.
- * </p>
- *
- * @since 1.7
- */
- public class ISINValidator implements Serializable {
- private static final long serialVersionUID = -5964391439144260936L;
- private static final String ISIN_REGEX = "([A-Z]{2}[A-Z0-9]{9}[0-9])";
- private static final CodeValidator VALIDATOR = new CodeValidator(ISIN_REGEX, 12, ISINCheckDigit.ISIN_CHECK_DIGIT);
- /** ISIN Code Validator (no countryCode check) */
- private static final ISINValidator ISIN_VALIDATOR_FALSE = new ISINValidator(false);
- /** ISIN Code Validator (with countryCode check) */
- private static final ISINValidator ISIN_VALIDATOR_TRUE = new ISINValidator(true);
- private static final String [] CCODES = Locale.getISOCountries();
- /**
- * All codes from ISO 3166-1 alpha-2 except unassigned code elements.
- *
- * From https://www.iso.org/obp/ui/#iso:pub:PUB500001:en as of 2024-03-23.
- */
- private static final String[] SPECIALS = {
- "AA",
- "AC",
- "AD",
- "AE",
- "AF",
- "AG",
- "AI",
- "AL",
- "AM",
- "AN",
- "AO",
- "AP",
- "AQ",
- "AR",
- "AS",
- "AT",
- "AU",
- "AW",
- "AX",
- "AZ",
- "BA",
- "BB",
- "BD",
- "BE",
- "BF",
- "BG",
- "BH",
- "BI",
- "BJ",
- "BL",
- "BM",
- "BN",
- "BO",
- "BQ",
- "BR",
- "BS",
- "BT",
- "BU",
- "BV",
- "BW",
- "BX",
- "BY",
- "BZ",
- "CA",
- "CC",
- "CD",
- "CF",
- "CG",
- "CH",
- "CI",
- "CK",
- "CL",
- "CM",
- "CN",
- "CO",
- "CP",
- "CQ",
- "CR",
- "CS",
- "CT",
- "CU",
- "CV",
- "CW",
- "CX",
- "CY",
- "CZ",
- "DD",
- "DE",
- "DG",
- "DJ",
- "DK",
- "DM",
- "DO",
- "DY",
- "DZ",
- "EA",
- "EC",
- "EE",
- "EF",
- "EG",
- "EH",
- "EM",
- "EP",
- "ER",
- "ES",
- "ET",
- "EU",
- "EV",
- "EW",
- "EZ",
- "FI",
- "FJ",
- "FK",
- "FL",
- "FM",
- "FO",
- "FQ",
- "FR",
- "FX",
- "GA",
- "GB",
- "GC",
- "GD",
- "GE",
- "GF",
- "GG",
- "GH",
- "GI",
- "GL",
- "GM",
- "GN",
- "GP",
- "GQ",
- "GR",
- "GS",
- "GT",
- "GU",
- "GW",
- "GY",
- "HK",
- "HM",
- "HN",
- "HR",
- "HT",
- "HU",
- "HV",
- "IB",
- "IC",
- "ID",
- "IE",
- "IL",
- "IM",
- "IN",
- "IO",
- "IQ",
- "IR",
- "IS",
- "IT",
- "JA",
- "JE",
- "JM",
- "JO",
- "JP",
- "JT",
- "KE",
- "KG",
- "KH",
- "KI",
- "KM",
- "KN",
- "KP",
- "KR",
- "KW",
- "KY",
- "KZ",
- "LA",
- "LB",
- "LC",
- "LF",
- "LI",
- "LK",
- "LR",
- "LS",
- "LT",
- "LU",
- "LV",
- "LY",
- "MA",
- "MC",
- "MD",
- "ME",
- "MF",
- "MG",
- "MH",
- "MI",
- "MK",
- "ML",
- "MM",
- "MN",
- "MO",
- "MP",
- "MQ",
- "MR",
- "MS",
- "MT",
- "MU",
- "MV",
- "MW",
- "MX",
- "MY",
- "MZ",
- "NA",
- "NC",
- "NE",
- "NF",
- "NG",
- "NH",
- "NI",
- "NL",
- "NO",
- "NP",
- "NQ",
- "NR",
- "NT",
- "NU",
- "NZ",
- "OA",
- "OM",
- "PA",
- "PC",
- "PE",
- "PF",
- "PG",
- "PH",
- "PI",
- "PK",
- "PL",
- "PM",
- "PN",
- "PR",
- "PS",
- "PT",
- "PU",
- "PW",
- "PY",
- "PZ",
- "QA",
- "QM",
- "QN",
- "QO",
- "QP",
- "QQ",
- "QR",
- "QS",
- "QT",
- "QU",
- "QV",
- "QW",
- "QX",
- "QY",
- "QZ",
- "RA",
- "RB",
- "RC",
- "RE",
- "RH",
- "RI",
- "RL",
- "RM",
- "RN",
- "RO",
- "RP",
- "RS",
- "RU",
- "RW",
- "SA",
- "SB",
- "SC",
- "SD",
- "SE",
- "SF",
- "SG",
- "SH",
- "SI",
- "SJ",
- "SK",
- "SL",
- "SM",
- "SN",
- "SO",
- "SR",
- "SS",
- "ST",
- "SU",
- "SV",
- "SX",
- "SY",
- "SZ",
- "TA",
- "TC",
- "TD",
- "TF",
- "TG",
- "TH",
- "TJ",
- "TK",
- "TL",
- "TM",
- "TN",
- "TO",
- "TP",
- "TR",
- "TT",
- "TV",
- "TW",
- "TZ",
- "UA",
- "UG",
- "UK",
- "UM",
- "UN",
- "US",
- "UY",
- "UZ",
- "VA",
- "VC",
- "VD",
- "VE",
- "VG",
- "VI",
- "VN",
- "VU",
- "WF",
- "WG",
- "WK",
- "WL",
- "WO",
- "WS",
- "WV",
- "XA",
- "XB",
- "XC",
- "XD",
- "XE",
- "XF",
- "XG",
- "XH",
- "XI",
- "XJ",
- "XK",
- "XL",
- "XM",
- "XN",
- "XO",
- "XP",
- "XQ",
- "XR",
- "XS",
- "XT",
- "XU",
- "XV",
- "XW",
- "XX",
- "XY",
- "XZ",
- "YD",
- "YE",
- "YT",
- "YU",
- "YV",
- "ZA",
- "ZM",
- "ZR",
- "ZW",
- "ZZ",
- };
- static {
- Arrays.sort(CCODES); // we cannot assume the codes are sorted
- Arrays.sort(SPECIALS); // Just in case ...
- }
- /**
- * Gets the singleton instance of the ISIN validator.
- *
- * @param checkCountryCode whether to check the country-code prefix or not
- * @return A singleton instance of the appropriate ISIN validator.
- */
- public static ISINValidator getInstance(final boolean checkCountryCode) {
- return checkCountryCode ? ISIN_VALIDATOR_TRUE : ISIN_VALIDATOR_FALSE;
- }
- private final boolean checkCountryCode;
- private ISINValidator(final boolean checkCountryCode) {
- this.checkCountryCode = checkCountryCode;
- }
- private boolean checkCode(final String code) {
- return Arrays.binarySearch(CCODES, code) >= 0
- ||
- Arrays.binarySearch(SPECIALS, code) >= 0
- ;
- }
- /**
- * Tests whether the code is a valid ISIN code after any transformation
- * by the validate routine.
- *
- * @param code The code to validate.
- * @return {@code true} if a valid ISIN
- * code, otherwise {@code false}.
- */
- public boolean isValid(final String code) {
- final boolean valid = VALIDATOR.isValid(code);
- if (valid && checkCountryCode) {
- return checkCode(code.substring(0, 2));
- }
- return valid;
- }
- /**
- * Checks the code is valid ISIN code.
- *
- * @param code The code to validate.
- * @return A valid ISIN code if valid, otherwise {@code null}.
- */
- public Object validate(final String code) {
- final Object validate = VALIDATOR.validate(code);
- if (validate != null && checkCountryCode) {
- return checkCode(code.substring(0, 2)) ? validate : null;
- }
- return validate;
- }
- }