All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.kyrychenko.utils.vin.VinGeneratorUtils Maven / Gradle / Ivy

The newest version!
/*
 * MIT License
 *
 * Copyright (c) 2018 Mykhailo Kyrychenko 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package de.kyrychenko.utils.vin;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Random;
import java.util.stream.Stream;

/**
 * Utility class providing help methods to generate vehicle identification number (VIN)
 */
public final class VinGeneratorUtils {
    private static final Random RANDOM = new Random();
    private static final String PREFIXES_FILE_NAME = "vin-prefixes.txt";
    private static final String ALLOWED_CHARS = "0123456789ABCDEFGHJKLMNPRSTUVWXYZ";

    private VinGeneratorUtils() {
        throw new RuntimeException("Utility class should not be initialized");
    }

    /**
     * Generate random VIN
     *
     * @return randomly generated VIN
     */
    public static String getRandomVin() {
        final Vin vinYear = getRandomVinStart();
        final StringBuilder vinBuilder = new StringBuilder();

        vinBuilder.append(vinYear.getWmi());
        vinBuilder.append(vinYear.getVds());
        vinBuilder.append(getRandomVinChar());
        vinBuilder.append(vinYear.getYear());

        for (int i = 0; i < 7; i++) {
            vinBuilder.append(getRandomVinChar());
        }

        final String vin = vinBuilder.toString();

        try {
            final char checkSumChar = VinValidatorUtils.getVinCheckSumChar(vin);

            return vin.substring(0, 8) + Character.toString(checkSumChar) + vin.substring(9);
        } catch (InvalidVinException ignored) {
            // should never happen, because here we calculate checksum for VIN generated by us
            // but checksum calculation could throw exception for validation of foreign VIN
            return null;
        }
    }

    private static char getRandomVinChar() {
        // '33' is length of ALLOWED_CHARS
        return ALLOWED_CHARS.charAt(RANDOM.nextInt(33));
    }

    private static Vin getRandomVinStart() {
        // '62178' is a number of lines in the file; + 1 to avoid reading of first line
        final int lineToRead = RANDOM.nextInt(62177) + 1;

        try (final Stream stream = Files.lines(Paths.get(ClassLoader.getSystemResource(PREFIXES_FILE_NAME).toURI()))) {
            final String line = stream.skip(lineToRead)
                    .findFirst()
                    .orElseThrow(() -> new RuntimeException("Problem occurred while read line " + lineToRead + " from " + PREFIXES_FILE_NAME));
            final String[] fields = line.split(" {3}");

            return new Vin(fields[0].trim(), fields[1].trim(), fields[2].trim());
        } catch (URISyntaxException | IOException | SecurityException e) {
            throw new RuntimeException("Problem occurred while reading " + PREFIXES_FILE_NAME, e);
        }
    }

    /**
     * Helper class used internally to save parts of VIN
     */
    private static class Vin {
        /**
         * WMI - (World Manufacturers Identification)
         */
        private final String wmi;

        /**
         * VDS (Vehicle Description Section)
         */
        private final String vds;

        /**
         * Year of model
         */
        private final String year;

        Vin(final String wmi,
            final String vds,
            final String year) {
            this.wmi = wmi;
            this.vds = vds;
            this.year = year;
        }

        String getWmi() {
            return this.wmi;
        }

        String getVds() {
            return this.vds;
        }

        String getYear() {
            return this.year;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy