import java.util.Collections;
import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class AlphabeticIDGenerator implements IDGenerator {
private static final char NULL_CHAR = '\u0000';
}
public synchronized boolean isValidID(String value) throws IllegalArgumentException {
- // Currently stubbed-out
- return true;
+
+ if ( value == null || value == "") {
+ throw new IllegalArgumentException("ID to validate must not be null or empty");
+ }
+
+ Pattern pattern = Pattern.compile(getRegex());
+ Matcher matcher = pattern.matcher(value);
+ if (matcher.matches()) {
+ return true;
+ } else {
+ return false;
+ }
+
}
-
+
+ public synchronized String getRegex() {
+ // @TODO: This method is stubbed out; it needs to be implemented.
+ String regex = "(" + "\\*" + ")";
+ return regex;
+ }
}
* $Date: 2009-06-19 19:03:38 -0700 (Fri, 19 Jun 2009) $
*/
+// @TODO: Consider making this class, or a class that implements
+// this interface, abstract, in part because we're duplicating code
+// in isValidID() in multiple Generator subclasses.
+
package org.collectionspace.services.id;
public interface IDGenerator {
public boolean isValidID(String value);
- // public String getRegex();
+ public String getRegex();
}
package org.collectionspace.services.id;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class NumericIDGenerator implements IDGenerator {
-
+
+ final static private int DEFAULT_MAX_LENGTH = 6;
+ private int maxLength = DEFAULT_MAX_LENGTH;
+
private long initialValue = 0;
private long currentValue = 0;
public NumericIDGenerator(String initialValue) throws IllegalArgumentException {
+ this(initialValue, Integer.toString(DEFAULT_MAX_LENGTH));
+ }
+
+ public NumericIDGenerator(String initialValue, String maxLength)
+ throws IllegalArgumentException {
+
try {
long l = Long.parseLong(initialValue.trim());
if ( l < 0 ) {
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Initial ID value must be parseable as a number");
}
+
+ try {
+ this.maxLength = Integer.parseInt(maxLength);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Maximum ID length must be parseable as a number");
+ }
+
}
public synchronized void reset() {
return Long.toString(this.currentValue);
}
- public synchronized String getNextID() {
+ public synchronized String getNextID() throws IllegalStateException {
this.currentValue++;
- return Long.toString(this.currentValue);
+ String nextID = Long.toString(this.currentValue);
+ if (nextID.length() > this.maxLength) {
+ throw new IllegalStateException("Next ID cannot exceed maximum length");
+ }
+ return nextID;
+ }
+
+ public synchronized boolean isValidID(String value) {
+
+ if ( value == null || value == "") {
+ return false;
+ }
+
+ Pattern pattern = Pattern.compile(getRegex());
+ Matcher matcher = pattern.matcher(value);
+ if (matcher.matches()) {
+ return true;
+ } else {
+ return false;
+ }
+
}
- public synchronized boolean isValidID(String value) throws IllegalArgumentException {
- // Currently stubbed-out
- return true;
+ public synchronized String getRegex() {
+ String regex = "(" + "\\d" + "{1," + Integer.toString(this.maxLength) + "}" + ")";
+ return regex;
}
}
public class NumericIDPart extends IDPart {
- public NumericIDPart(String baseVal) {
+ public NumericIDPart(String baseVal) throws IllegalArgumentException {
// Store the appropriate Numeric ID generator and the base value for this part.
-
- // @TODO: Determine how to handle the NumberFormatException that will be thrown
- // from parseLong "if the string does not contain a parsable long." We may
- // need a shim to perform this conversion prior to setting up the generator.
super(new NumericIDGenerator(baseVal));
};
+ public NumericIDPart(String baseVal, String maxLength) throws IllegalArgumentException {
+ super(new NumericIDGenerator(baseVal, maxLength));
+ };
+
}
}
+ public void testNextIDOverflow() {
+
+ try {
+ part = new NumericIDPart("997", "3");
+ assertEquals("998", part.getNextID());
+ assertEquals("999", part.getNextID());
+ assertEquals("1000", part.getNextID());
+ fail("Should have thrown IllegalStateException here");
+ } catch (IllegalStateException expected) {
+ // This Exception should be thrown, and thus the test should pass.
+ }
+
+ // Tests default MAX_LENGTH value of 6 decimal places
+ try {
+ part = new NumericIDPart("999997");
+ assertEquals("999998", part.getNextID());
+ assertEquals("999999", part.getNextID());
+ assertEquals("1000000", part.getNextID());
+ fail("Should have thrown IllegalStateException here");
+ } catch (IllegalStateException expected) {
+ // This Exception should be thrown, and thus the test should pass.
+ }
+
+ }
+
public void testReset() {
part = new NumericIDPart("25");
}
}
+
+ public void testNonLongParseableMaxLength() {
+
+ try {
+ part = new NumericIDPart("1", "not an int parseable value");
+ fail("Should have thrown IllegalArgumentException here");
+ } catch (IllegalArgumentException expected) {
+ // This Exception should be thrown, and thus the test should pass.
+ }
+
+ }
+
+ public void testIsValidID() {
+
+ part = new NumericIDPart("1");
+ assertTrue(part.isValidID("1"));
+
+ part = new NumericIDPart("1");
+ assertTrue(part.isValidID("123"));
+
+ part = new NumericIDPart("1");
+ assertTrue(part.isValidID("123456"));
+
+ part = new NumericIDPart("1");
+ assertFalse(part.isValidID("1234567"));
+
+ part = new NumericIDPart("1", "3");
+ assertTrue(part.isValidID("123"));
+
+ part = new NumericIDPart("1", "3");
+ assertFalse(part.isValidID("1234"));
+
+ part = new NumericIDPart("1");
+ assertFalse(part.isValidID("not a parseable long"));
+
+ part = new NumericIDPart("1", "3");
+ assertFalse(part.isValidID("not a parseable long"));
+
+ }
// @TODO: Add more tests of boundary conditions, exceptions ...