1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.id.serial;
18
19 import org.apache.commons.id.AbstractStringIdentifierGenerator;
20
21 /**
22 * <code>PrefixedLeftPaddedNumericGenerator</code> is an Identifier Generator
23 * that generates a left-padded incrementing number with a prefix as a String object.
24 *
25 * <p>All generated ids have the same length (prefixed and padded with 0's
26 * on the left), which is determined by the <code>size</code> parameter passed
27 * to the constructor.<p>
28 *
29 * <p>The <code>wrap</code> property determines whether or not the sequence wraps
30 * when it reaches the largest value that can be represented in <code>size</code>
31 * base 10 digits. If <code>wrap</code> is false and the the maximum representable
32 * value is exceeded, an {@link IllegalStateException} is thrown.</p>
33 *
34 * @author Commons-Id team
35 * @version $Id$
36 */
37 public class PrefixedLeftPaddedNumericGenerator extends AbstractStringIdentifierGenerator {
38
39 /** Prefix. */
40 private final String prefix;
41
42 /** Should the counter wrap. */
43 private boolean wrap = true;
44
45 /** The counter. */
46 private char[] count = null;
47
48 /** '9' char. */
49 private static final char NINE_CHAR = '9';
50
51
52 /**
53 * Create a new prefixed left-padded numeric generator with the specified prefix.
54 *
55 * @param prefix prefix, must not be null or empty
56 * @param wrap should the factory wrap when it reaches the maximum
57 * value that can be represented in <code>size</code> base 10 digits
58 * (or throw an exception)
59 * @param size the size of the identifier, including prefix length
60 * @throws IllegalArgumentException if size less prefix length is not at least one
61 * @throws NullPointerException if prefix is <code>null</code>
62 */
63 public PrefixedLeftPaddedNumericGenerator(String prefix, boolean wrap, int size) {
64 super();
65
66 if (prefix == null) {
67 throw new NullPointerException("prefix must not be null");
68 }
69 if (size < 1) {
70 throw new IllegalArgumentException("size must be at least one");
71 }
72 if (size <= prefix.length()) {
73 throw new IllegalArgumentException("size less prefix length must be at least one");
74 }
75 this.wrap = wrap;
76 this.prefix = prefix;
77
78 int countLength = size - prefix.length();
79 this.count = new char[countLength];
80 for (int i = 0; i < countLength; i++) {
81 count[i] = '0';
82 }
83 }
84
85
86 /**
87 * Return the prefix for this prefixed numeric generator.
88 *
89 * @return the prefix for this prefixed numeric generator
90 */
91 public String getPrefix() {
92 return prefix;
93 }
94
95 public long maxLength() {
96 return this.count.length + prefix.length();
97 }
98
99 public long minLength() {
100 return this.count.length + prefix.length();
101 }
102
103 /**
104 * Returns the (constant) size of the strings generated by this generator.
105 *
106 * @return the size of generated identifiers
107 */
108 public int getSize() {
109 return this.count.length + prefix.length();
110 }
111
112 /**
113 * Getter for property wrap.
114 *
115 * @return <code>true</code> if this generator is set up to wrap
116 */
117 public boolean isWrap() {
118 return wrap;
119 }
120
121 /**
122 * Setter for property wrap.
123 *
124 * @param wrap should the factory wrap when it reaches the maximum
125 * value that can be represented in <code>size</code> base 10 digits
126 * (or throw an exception)
127 */
128 public void setWrap(boolean wrap) {
129 this.wrap = wrap;
130 }
131
132 public String nextStringIdentifier() {
133 for (int i = count.length - 1; i >= 0; i--) {
134 switch (count[i]) {
135 case NINE_CHAR: // 9
136 count[i] = '0';
137 if (i == 0 && !wrap) {
138 throw new IllegalStateException
139 ("The maximum number of identifiers has been reached");
140 }
141 break;
142
143 default:
144 count[i]++;
145 i = -1;
146 break;
147 }
148 }
149
150 StringBuffer sb = new StringBuffer(prefix);
151 sb.append(count);
152 return sb.toString();
153 }
154 }