001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.validator.routines.checkdigit;
018    
019    import java.io.Serializable;
020    
021    
022    /**
023     * Modulus 10 <b>Luhn</b> Check Digit calculation/validation.
024     * <p>
025     * Luhn check digits are used, for example, by:
026     * <ul>
027     *    <li><a href="http://en.wikipedia.org/wiki/Credit_card">Credit Card Numbers</a></li>
028     *    <li><a href="http://en.wikipedia.org/wiki/IMEI">IMEI Numbers</a> - International
029     *        Mobile Equipment Identity Numbers</li>
030     * </ul>
031     * Check digit calculation is based on <i>modulus 10</i> with digits in
032     * an <i>odd</i> position (from right to left) being weighted 1 and <i>even</i>
033     * position digits being weighted 2 (weighted values greater than 9 have 9 subtracted).
034     * <p>
035     * See <a href="http://en.wikipedia.org/wiki/Luhn_algorithm">Wikipedia</a>
036     * for more details.
037     *
038     * @version $Revision: 493905 $ $Date: 2007-01-08 03:11:38 +0100 (Mo, 08. Jan 2007) $
039     * @since Validator 1.4
040     */
041    public final class LuhnCheckDigit extends ModulusCheckDigit implements Serializable {
042    
043        /** Singleton Luhn Check Digit instance */
044        public static final CheckDigit INSTANCE = new LuhnCheckDigit();
045    
046        /** weighting given to digits depending on their right position */
047        private static final int[] POSITION_WEIGHT = new int[] {2, 1};
048    
049        /**
050         * Construct a modulus 10 Luhn Check Digit routine.
051         */
052        public LuhnCheckDigit() {
053            super(10);
054        }
055    
056        /**
057         * <p>Calculates the <i>weighted</i> value of a charcter in the
058         * code at a specified position.</p>
059         *
060         * <p>For Luhn (from right to left) <b>odd</b> digits are weighted
061         * with a factor of <b>one</b> and <b>even</b> digits with a factor
062         * of <b>two</b>. Weighted values > 9, have 9 subtracted</p>
063         *
064         * @param charValue The numeric value of the character.
065         * @param leftPos The position of the character in the code, counting from left to right 
066         * @param rightPos The positionof the character in the code, counting from right to left
067         * @return The weighted value of the character.
068         */
069        protected int weightedValue(int charValue, int leftPos, int rightPos) {
070            int weight = POSITION_WEIGHT[rightPos % 2];
071            int weightedValue = (charValue * weight);
072            return (weightedValue > 9 ? (weightedValue - 9) : weightedValue);
073        }
074    }