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
18 package org.apache.commons.id.serial;
19
20 import org.apache.commons.id.AbstractStringIdentifierGenerator;
21
22 import java.io.Serializable;
23
24 /**
25 * <code>AlphanumericGenerator</code> is an identifier generator
26 * that generates an incrementing number in base 36 as a String
27 * object.
28 *
29 * <p>All generated ids have the same length (padding with 0's on the left),
30 * which is determined by the <code>size</code> parameter passed to the constructor.<p>
31 *
32 * <p>The <code>wrap</code> property determines whether or not the sequence wraps
33 * when it reaches the largest value that can be represented in <code>size</code>
34 * base 36 digits. If <code>wrap</code> is false and the the maximum representable
35 * value is exceeded, an IllegalStateException is thrown</p>
36 *
37 * @author Commons-Id team
38 * @version $Id: AlphanumericGenerator.java 480488 2006-11-29 08:57:26Z bayard $
39 */
40 public class AlphanumericGenerator extends AbstractStringIdentifierGenerator implements Serializable {
41
42 /**
43 * <code>serialVersionUID</code> is the serializable UID for the binary version of the class.
44 */
45 private static final long serialVersionUID = 20060120L;
46
47 /**
48 * Should the counter wrap.
49 */
50 private boolean wrapping = true;
51
52 /**
53 * The counter.
54 */
55 private char[] count = null;
56
57 /**
58 * 'z' char
59 */
60 private static final char Z_CHAR = 'z';
61
62 /**
63 * '9' char
64 */
65 private static final char NINE_CHAR = '9';
66
67 /**
68 * Constructor with a default size for the alphanumeric identifier.
69 *
70 * @param wrap should the factory wrap when it reaches the maximum
71 * long value (or throw an exception)
72 */
73 public AlphanumericGenerator(boolean wrap) {
74 this(wrap, DEFAULT_ALPHANUMERIC_IDENTIFIER_SIZE);
75 }
76
77 /**
78 * Constructor.
79 *
80 * @param wrap should the factory wrap when it reaches the maximum
81 * long value (or throw an exception)
82 * @param size the size of the identifier
83 */
84 public AlphanumericGenerator(boolean wrap, int size) {
85 super();
86 this.wrapping = wrap;
87 if (size < 1) {
88 throw new IllegalArgumentException("The size must be at least one");
89 }
90 this.count = new char[size];
91 for (int i = 0; i < size; i++) {
92 count[i] = '0'; // zero
93 }
94 }
95
96 /**
97 * Construct with a counter, that will start at the specified
98 * alphanumeric value.</p>
99 *
100 * @param wrap should the factory wrap when it reaches the maximum
101 * value (or throw an exception)
102 * @param initialValue the initial value to start at
103 */
104 public AlphanumericGenerator(boolean wrap, String initialValue) {
105 super();
106 this.wrapping = wrap;
107 this.count = initialValue.toCharArray();
108
109 for (int i = 0; i < this.count.length; i++) {
110 char ch = this.count[i];
111 if (ch >= '0' && ch <= '9') continue;
112 if (ch >= 'a' && ch <= 'z') continue;
113
114 throw new IllegalArgumentException(
115 "character " + this.count[i] + " is not valid");
116 }
117 }
118
119 public long maxLength() {
120 return this.count.length;
121 }
122
123 public long minLength() {
124 return this.count.length;
125 }
126
127 /**
128 * Getter for property wrap.
129 *
130 * @return <code>true</code> if this generator is set up to wrap.
131 *
132 */
133 public boolean isWrap() {
134 return wrapping;
135 }
136
137 /**
138 * Sets the wrap property.
139 *
140 * @param wrap value for the wrap property
141 *
142 */
143 public void setWrap(boolean wrap) {
144 this.wrapping = wrap;
145 }
146
147 /**
148 * Returns the (constant) size of the strings generated by this generator.
149 *
150 * @return the size of generated identifiers
151 */
152 public int getSize() {
153 return this.count.length;
154 }
155
156 public synchronized String nextStringIdentifier() {
157 for (int i = count.length - 1; i >= 0; i--) {
158 switch (count[i]) {
159 case Z_CHAR: // z
160 if (i == 0 && !wrapping) {
161 throw new IllegalStateException
162 ("The maximum number of identifiers has been reached");
163 }
164 count[i] = '0';
165 break;
166
167 case NINE_CHAR: // 9
168 count[i] = 'a';
169 i = -1;
170 break;
171
172 default:
173 count[i]++;
174 i = -1;
175 break;
176 }
177 }
178 return new String(count);
179 }
180 }