package com.baiyue.common.event; import java.util.Locale; /** Canonical physical container number used by cross-region business facts. */ public final class ContainerNumbers { private static final int[] LETTER_VALUES = { 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38 }; private ContainerNumbers() { } public static String normalizeRequired(String value) { if (value == null || value.isBlank()) { throw new IllegalArgumentException("containerNo is required"); } StringBuilder compact = new StringBuilder(value.length()); value.codePoints().filter(codePoint -> !Character.isWhitespace(codePoint) && !Character.isSpaceChar(codePoint)).forEach(compact::appendCodePoint); String normalized = compact.toString().toUpperCase(Locale.ROOT); if (!normalized.matches("[A-Z]{3}[UJZ][0-9]{7}")) { throw new IllegalArgumentException("containerNo must comply with ISO 6346"); } int sum = 0; for (int index = 0; index < 10; index++) { char current = normalized.charAt(index); int number = Character.isDigit(current) ? current - '0' : LETTER_VALUES[current - 'A']; sum += number * (1 << index); } if (normalized.charAt(10) - '0' != sum % 11 % 10) { throw new IllegalArgumentException("containerNo must comply with ISO 6346 check digit"); } return normalized; } public static String requireCanonical(String value) { String normalized = normalizeRequired(value); if (!normalized.equals(value)) { throw new IllegalArgumentException("containerNo must be normalized"); } return normalized; } }