ECNumberCheckDigit.java

  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.checkdigit;

  18. import org.apache.commons.validator.GenericValidator;
  19. import org.apache.commons.validator.routines.CodeValidator;

  20. /**
  21.  * Modulus 11 <b>EC number</b> Check Digit calculation/validation.
  22.  *
  23.  * <p>
  24.  * The European Community number (EC number) is a unique seven-digit identifier
  25.  * that is assigned to chemical substances.
  26.  * For example, the EC number of arsenic is 231-148-6:
  27.  * </p>
  28.  *
  29.  * <p>
  30.  * Check digit calculation is based on <i>modulus 11</i> with digits being weighted
  31.  * based on their position (from left to right).
  32.  * </p>
  33.  *
  34.  * <p>
  35.  * For further information see
  36.  *  <a href="https://en.wikipedia.org/wiki/European_Community_number">Wikipedia - EC number</a>.
  37.  * </p>
  38.  *
  39.  * @since 1.9.0
  40.  */
  41. public final class ECNumberCheckDigit extends ModulusCheckDigit {

  42.     private static final long serialVersionUID = 7265356024784308367L;

  43.     /** Singleton Check Digit instance */
  44.     private static final ECNumberCheckDigit INSTANCE = new ECNumberCheckDigit();

  45.     /**
  46.      * Gets the singleton instance of this validator.
  47.      * @return A singleton instance of the EC Number validator.
  48.      */
  49.     public static CheckDigit getInstance() {
  50.         return INSTANCE;
  51.     }

  52.     /**
  53.      * EC number consists of 3 groups of numbers separated dashes (-).
  54.      * Example: dexamethasone is 200-003-9
  55.      */
  56.     private static final String GROUP = "(\\d{3})";
  57.     private static final String DASH = "(?:\\-)";
  58.     static final String EC_REGEX = "^(?:" + GROUP + DASH + GROUP + DASH + "(\\d))$";

  59.     private static final int EC_LEN = 7;
  60.     static final CodeValidator REGEX_VALIDATOR = new CodeValidator(EC_REGEX, EC_LEN, null);

  61.     /**
  62.      * Constructs a modulus 11 Check Digit routine.
  63.      */
  64.     private ECNumberCheckDigit() {
  65.         super(MODULUS_11);
  66.     }

  67.     /**
  68.      * Calculates the <i>weighted</i> value of a character in the
  69.      * code at a specified position.
  70.      *
  71.      * <p>For EC number digits are weighted by their position from left to right.</p>
  72.      *
  73.      * @param charValue The numeric value of the character.
  74.      * @param leftPos The position of the character in the code, counting from left to right
  75.      * @param rightPos The positionof the character in the code, counting from right to left
  76.      * @return The weighted value of the character.
  77.      */
  78.     @Override
  79.     protected int weightedValue(final int charValue, final int leftPos, final int rightPos) {
  80.         return leftPos >= EC_LEN ? 0 : charValue * leftPos;
  81.     }

  82.     /**
  83.      * {@inheritDoc}
  84.      */
  85.     @Override
  86.     public String calculate(final String code) throws CheckDigitException {
  87.         if (GenericValidator.isBlankOrNull(code)) {
  88.             throw new CheckDigitException("Code is missing");
  89.         }
  90.         final int modulusResult = INSTANCE.calculateModulus(code, false);
  91.         return toCheckDigit(modulusResult);
  92.     }

  93.     /**
  94.      * {@inheritDoc}
  95.      */
  96.     @Override
  97.     public boolean isValid(final String code) {
  98.         if (GenericValidator.isBlankOrNull(code)) {
  99.             return false;
  100.         }
  101.         final Object cde = REGEX_VALIDATOR.validate(code);
  102.         if (!(cde instanceof String)) {
  103.             return false;
  104.         }
  105.         try {
  106.             final int modulusResult = INSTANCE.calculateModulus((String) cde, true);
  107.             return modulusResult == Character.getNumericValue(code.charAt(code.length() - 1));
  108.         } catch (final CheckDigitException ex) {
  109.             return false;
  110.         }
  111.     }

  112. }