001    /*
002     * The MIT License
003     *
004     * Copyright (c) 2013, Ninja Squad
005     *
006     * Permission is hereby granted, free of charge, to any person obtaining a copy
007     * of this software and associated documentation files (the "Software"), to deal
008     * in the Software without restriction, including without limitation the rights
009     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010     * copies of the Software, and to permit persons to whom the Software is
011     * furnished to do so, subject to the following conditions:
012     *
013     * The above copyright notice and this permission notice shall be included in
014     * all copies or substantial portions of the Software.
015     *
016     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
022     * THE SOFTWARE.
023     */
024    
025    package com.ninja_squad.dbsetup.generator;
026    
027    import com.ninja_squad.dbsetup.util.Preconditions;
028    
029    /**
030     * A {@link ValueGenerator} that returns a string prefix followed by a sequence number, optionally left-padded
031     * with 0 to ensure a correct ordering (for example: CODE_001, CODE_002, etc.). Instances of this generator
032     * are created by {@link ValueGenerators#stringSequence(String)}.
033     * @author JB
034     */
035    public final class StringSequenceValueGenerator implements ValueGenerator<String> {
036        private String prefix;
037        private long next;
038        private int increment;
039    
040        /**
041         * The length of the number once padded. 0 if no padding must be applied
042         */
043        private int paddedNumberLength;
044    
045        StringSequenceValueGenerator(String prefix) {
046            this(prefix, 1L, 1, 0);
047        }
048    
049        private StringSequenceValueGenerator(String prefix, long next, int increment, int paddedNumberLength) {
050            this.prefix = prefix;
051            this.next = next;
052            this.increment = increment;
053            this.paddedNumberLength = paddedNumberLength;
054        }
055    
056        /**
057         * Tells the generator to left-pad the number it generates with 0 until the length of the number is the given
058         * length. For example, passing 3 to this method will generate numbers 001, 002, 003, 004, etc. If the generated
059         * number, before padding, has a length already equal or larger that the given length, the number is not padded.
060         * @param paddedNumberLength the length of the number once padded. Must be > 0.
061         * @return this instance, for chaining
062         */
063        public StringSequenceValueGenerator withLeftPadding(int paddedNumberLength) {
064            Preconditions.checkArgument(paddedNumberLength > 0, "paddedNumberLength must be > 0");
065            this.paddedNumberLength = paddedNumberLength;
066            return this;
067        }
068    
069        /**
070         * Tells the generator to avoid left-padding the number it generates with 0
071         * @return this instance, for chaining
072         */
073        public StringSequenceValueGenerator withoutLeftPadding() {
074            this.paddedNumberLength = 0;
075            return this;
076        }
077    
078        /**
079         * Restarts the sequence at the given value
080         * @param start the new starting value of the sequence
081         * @return this instance, for chaining
082         */
083        public StringSequenceValueGenerator startingAt(long start) {
084            this.next = start;
085            return this;
086        }
087    
088        /**
089         * Increments the number by the given increment.
090         * @return this instance, for chaining
091         */
092        public StringSequenceValueGenerator incrementingBy(int increment) {
093            this.increment = increment;
094            return this;
095        }
096    
097        @Override
098        public String nextValue() {
099            long number = next;
100            next += increment;
101            return prefix + leftPadIfNecessary(number);
102        }
103    
104        private String leftPadIfNecessary(long number) {
105            String numberAsString = Long.toString(number);
106            if (numberAsString.length() >= paddedNumberLength) {
107                return numberAsString;
108            }
109            StringBuilder builder = new StringBuilder(paddedNumberLength);
110            for (int i = 0; i < paddedNumberLength - numberAsString.length(); i++) {
111                builder.append('0');
112            }
113            return builder.append(numberAsString).toString();
114        }
115    
116        @Override
117        public String toString() {
118            return "StringSequenceValueGenerator["
119                   + "prefix='" + prefix + '\''
120                   + ", next=" + next
121                   + ", increment=" + increment
122                   + ", paddedNumberLength=" + paddedNumberLength
123                   + "]";
124        }
125    }