001// -------------------------------------------------------------------------------- 002// Copyright 2002-2024 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.model.control.sequence.server.logic.checksum; 018 019import com.echothree.model.control.sequence.server.logic.SequenceGeneratorLogic; 020import com.google.common.base.Charsets; 021 022public class Mod36SequenceChecksum 023 implements SequenceChecksum { 024 025 private Mod36SequenceChecksum() { 026 super(); 027 } 028 029 private static class SequenceChecksumHolder { 030 static SequenceChecksum instance = new Mod36SequenceChecksum(); 031 } 032 033 public static SequenceChecksum getInstance() { 034 return SequenceChecksumHolder.instance; 035 } 036 037 @Override 038 public String calculate(String value) { 039 var bytes = value.getBytes(Charsets.UTF_8); 040 int sum = 0; 041 042 for(int i = 0 ; i < bytes.length; i++) { 043 sum += (bytes [i] * (i + 1)); 044 } 045 046 char[] modCharacter = { SequenceGeneratorLogic.ALPHANUMERIC_VALUES.charAt(sum % SequenceGeneratorLogic.ALPHANUMERIC_MAX_INDEX) }; 047 return new String(modCharacter); 048 } 049 050 @Override 051 public String regexp() { 052 return "[\\p{Upper}\\p{Digit}]"; 053 } 054 055 @Override 056 public boolean verify(String value) { 057 var codePoints = value.codePoints().toArray(); 058 var length = codePoints.length; 059 var valueWithoutChecksum = new String(codePoints, 0, length - 1); 060 var checksumFromValue = new String(codePoints, length - 1, 1); 061 var checksum = calculate(valueWithoutChecksum); 062 063 return checksumFromValue.equals(checksum); 064 } 065 066}