]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
NOJIRA Experiments with ID Parts and Generators, for potential use with the ID Service.
authorAron Roberts <aron@socrates.berkeley.edu>
Sat, 20 Jun 2009 02:03:38 +0000 (02:03 +0000)
committerAron Roberts <aron@socrates.berkeley.edu>
Sat, 20 Jun 2009 02:03:38 +0000 (02:03 +0000)
sandbox/aron/id/pom.xml [new file with mode: 0644]
sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticGenerator.java [new file with mode: 0644]
sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticSeriesIDPart.java [new file with mode: 0644]
sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPart.java [new file with mode: 0644]
sandbox/aron/id/src/main/java/org/collectionspace/services/id/SeriesIDPart.java [new file with mode: 0644]
sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticGeneratorTest.java [new file with mode: 0644]
sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticSeriesIDPartTest.java [new file with mode: 0644]
sandbox/aron/id/third-party/commons-id-1.0-SNAPSHOT.jar [new file with mode: 0644]
sandbox/aron/id/third-party/install-third-party.sh [new file with mode: 0644]

diff --git a/sandbox/aron/id/pom.xml b/sandbox/aron/id/pom.xml
new file mode 100644 (file)
index 0000000..60292ca
--- /dev/null
@@ -0,0 +1,35 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.collectionspace.services</groupId>
+  <artifactId>id</artifactId>
+  <packaging>jar</packaging>
+  <version>0.1-SNAPSHOT</version>
+  <name>id</name>
+  <url>http://maven.apache.org</url>
+  <build>
+       <plugins>
+       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.5</source>
+                                       <target>1.5</target>
+                               </configuration>
+                               </plugin>
+                       </plugins>
+               </build>
+               <dependencies>
+               <dependency>
+                       <groupId>org.apache.commons</groupId>
+                       <artifactId>commons-id</artifactId>
+      <version>1.0-SNAPSHOT</version>
+               </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+       </dependencies>
+</project>
diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticGenerator.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticGenerator.java
new file mode 100644 (file)
index 0000000..0633ff1
--- /dev/null
@@ -0,0 +1,212 @@
+ /*    
+ * AlphabeticGenerator
+ *
+ * <p>An identifier generator that generates an incrementing ID from any composite
+ * of the USASCII character sequences 'A-Z' and 'a-z', as a String object.</p>
+ *
+ * <p>The <code>wrap</code> property determines whether or not the sequence wraps
+ * when it reaches the largest value that can be represented in <code>size</code>.
+ * If <code>wrap</code> is false and the the maximum representable
+ * value is exceeded, an IllegalStateException is thrown</p>
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+// @TODO: The initial value determines the fixed number of characters.
+// We may also need to model cases where the number of characters
+// increases as values roll over, up to a specified maximum number of
+// characters; e.g. "z" becomes "aa", and "ZZ" becomes "AAA".
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+package org.collectionspace.services.id;
+
+import org.apache.commons.id.AbstractStringIdentifierGenerator;
+import java.io.Serializable;
+
+public class AlphabeticGenerator extends AbstractStringIdentifierGenerator
+       implements Serializable {
+
+    /**
+     * <code>serialVersionUID</code> is the serializable UID for the binary version of the class.
+     */
+    // private static final long serialVersionUID = 20060120L;  // @TODO ReplaceMe!
+
+    /**
+     * Should the counter wrap.
+     */
+    private boolean wrapping = true;
+
+    /**
+     * The counter.
+     */
+    private char[] count = null;
+    private char[] initialcount = null;
+
+    /**
+     * 'Z' and 'z' chars
+     */
+    private static final char LOWERCASE_Z_CHAR = 'z';
+    private static final char UPPERCASE_Z_CHAR = 'Z';
+
+    /**
+     * Constructor with a default size for the alphanumeric identifier.
+     *
+     * @param wrap should the factory wrap when it reaches the maximum
+     *   value (or throw an exception)
+     */
+    public AlphabeticGenerator(boolean wrap) {
+        this(wrap, DEFAULT_ALPHANUMERIC_IDENTIFIER_SIZE);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param wrap should the factory wrap when it reaches the maximum
+     *   value (or throw an exception)
+     * @param size  the size of the identifier
+     */
+    public AlphabeticGenerator(boolean wrap, int size) {
+        super();
+        this.wrapping = wrap;
+        if (size < 1) {
+            throw new IllegalArgumentException("The size must be at least one");
+        }
+        this.count = new char[size];
+        
+        // Initialize the contents of the identifier's character array
+        for (int i = 0; i < size; i++) {
+            count[i] = ' ';  // space
+        }
+    }
+
+    /**
+     * Construct with a counter, that will start at the specified
+     * alphanumeric value.</p>
+     *
+     * @param wrap should the factory wrap when it reaches the maximum
+     * value (or throw an exception)
+     * @param initialValue the initial value to start at
+     */
+    public AlphabeticGenerator(boolean wrap, String initialValue) {
+        super();
+        this.wrapping = wrap;
+                               if ( initialValue == null ) {
+                                       throw new IllegalArgumentException("Initial value must not be null");
+                               }
+
+                               if ( initialValue == "" ) {
+                                       throw new IllegalArgumentException("Initial value must not be empty");
+                               }
+
+       this.count = initialValue.toCharArray();
+
+        // Validate each of the characters in the initial value
+        // against ranges of valid values.
+        for (int i = 0; i < this.count.length; i++) {
+            char ch = this.count[i];
+            if (ch >= 'A' && ch <= 'Z') continue;
+            if (ch >= 'a' && ch <= 'z') continue;
+            
+            throw new IllegalArgumentException(
+                    "character " + this.count[i] + " is not valid");
+        }
+        
+        // Store the initial character array
+        this.initialcount = this.count;
+    }
+    
+    public long maxLength() {
+        return this.count.length;
+    }
+
+    public long minLength() {
+        return this.count.length;
+    }
+
+    /**
+     * Getter for property wrap.
+     *
+     * @return <code>true</code> if this generator is set up to wrap.
+     *
+     */
+    public boolean isWrap() {
+        return wrapping;
+    }
+
+    /**
+     * Sets the wrap property.
+     *
+     * @param wrap value for the wrap property
+     *
+     */
+    public void setWrap(boolean wrap) {
+        this.wrapping = wrap;
+    }
+
+    /**
+     * Returns the (constant) size of the strings generated by this generator.
+     *
+     * @return the size of generated identifiers
+     */
+    public int getSize() {
+        return this.count.length;
+    }
+
+    public synchronized String nextStringIdentifier() {
+        
+        // Get next values for each character from right to left
+        for (int i = count.length - 1; i >= 0; i--) {
+            switch (count[i]) {
+            
+                case LOWERCASE_Z_CHAR:  // z
+                    if (i == 0 && !wrapping) {
+                        throw new IllegalStateException
+                        ("The maximum number of identifiers has been reached");
+                    }
+                    count[i] = 'a';
+                    break;
+
+               case UPPERCASE_Z_CHAR:  // Z
+                    if (i == 0 && !wrapping) {
+                        throw new IllegalStateException
+                        ("The maximum number of identifiers has been reached");
+                    }
+                    count[i] = 'A';
+                    break;
+
+                default:
+                    count[i]++;
+                    i = -1;
+                    break;
+            }
+        }
+        return new String(count);
+    }
+}
diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticSeriesIDPart.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticSeriesIDPart.java
new file mode 100644 (file)
index 0000000..26e32a4
--- /dev/null
@@ -0,0 +1,33 @@
+ /*    
+ * AlphabeticSeriesIDPart
+ *
+ * Models a part of an identifier (ID) whose value is alphabetic,
+ * and increments within a series of uppercase and/or lowercase values
+ * in the USASCII character sequence.
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+package org.collectionspace.services.id;
+
+import org.apache.commons.id.StringIdentifierGenerator;
+
+public class AlphabeticSeriesIDPart extends SeriesIDPart {
+
+       public AlphabeticSeriesIDPart(String baseVal) {
+               // Store the appropriate Alphabetic ID generator and the base value for this part
+               // Value 'false' refers to the NO_WRAP behavior of the StringIdentifierGenerator.
+               super(new AlphabeticGenerator(false, baseVal), baseVal);
+       };
+}
diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPart.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPart.java
new file mode 100644 (file)
index 0000000..90ac7a4
--- /dev/null
@@ -0,0 +1,55 @@
+ /*    
+ * IDPart
+ *
+ * Models a part of an identifier (ID), such as (for instance) an incrementing
+ * numeric or alphabetic value, a date value, or a static separator.
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+package org.collectionspace.services.id;
+
+import org.apache.commons.id.StringIdentifierGenerator;
+
+public abstract class IDPart {
+
+       // Flags to identify whether series-based identifiers
+       // wrap to their initial values, after the last value
+       // in the series is reached.
+       final boolean WRAP = true;
+       final boolean NO_WRAP = false;
+       
+       // An identifier generator
+       protected StringIdentifierGenerator generator;
+       
+       // Constructor
+       public IDPart(StringIdentifierGenerator idGenerator) {
+               setGenerator(idGenerator);
+       }
+
+       // Sets the identifier generator
+       protected void setGenerator(StringIdentifierGenerator idGenerator) {
+               if (idGenerator != null) {
+                       generator = idGenerator;
+               }
+       }
+
+       // Gets the next identifier
+       public String nextIdentifier() {
+               // @TODO: Add Exception-handling here ...
+               return generator.nextStringIdentifier();
+       };
+
+       // public boolean validate() {};
+}
diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/SeriesIDPart.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/SeriesIDPart.java
new file mode 100644 (file)
index 0000000..9c92f6c
--- /dev/null
@@ -0,0 +1,71 @@
+ /*    
+ * SeriesIDPart
+ *
+ * Models a part of an identifier (ID) whose values are part of a series,
+ * such as (for instance) an incrementing numeric or alphabetic value.
+ * Values begin at an initial (base) value
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+ package org.collectionspace.services.id;
+
+import org.apache.commons.id.StringIdentifierGenerator;
+
+public abstract class SeriesIDPart extends IDPart {
+
+       protected String baseValue = "";
+       protected String lastIdGenerated = null;
+       
+       public SeriesIDPart(StringIdentifierGenerator idGenerator, String baseVal) {
+               // Store the identifier generator and base value,
+               // and set the current value to the base value
+               super(idGenerator);
+               setBaseValue(baseVal);
+       }
+
+       // Store the base value
+       protected void setBaseValue(String baseVal) {
+               // @TODO: Throw an Exception if the base value is null.
+               if (baseVal != null) {
+                       baseValue = baseVal;
+               }
+       };
+
+       // Get the base value
+       public String getBaseValue() {
+               return baseValue;
+       };
+
+       // Get the next identifier in series
+       public String nextIdentifier() {
+               // @TODO: Add Exception-handling here ...
+               // If no identifier has ever been generated,
+               // or if the value of the last identifier was reset,
+               // return the base value.
+               if (lastIdGenerated == null) {
+                       lastIdGenerated = baseValue;
+                       return lastIdGenerated;
+               // Otherwise, return the next value in the series.
+               } else {
+                       lastIdGenerated = generator.nextStringIdentifier();
+                       return lastIdGenerated;
+               }
+       }
+
+       // Reset the value of the last identifier generated.
+       public void reset() {
+               lastIdGenerated = null;
+       };
+        
+}
diff --git a/sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticGeneratorTest.java b/sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticGeneratorTest.java
new file mode 100644 (file)
index 0000000..34d297f
--- /dev/null
@@ -0,0 +1,198 @@
+ /*    
+ * AlphabeticGeneratorTest
+ *
+ * Test class for AlphabeticGenerator.
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// See <http://radio.javaranch.com/lasse/2007/05/17/1179405760728.html>
+// for Exception handling in JUnit.
+
+package org.collectionspace.services.id;
+
+import org.apache.commons.id.StringIdentifierGenerator;
+import static org.junit.Assert.fail;
+import junit.framework.TestCase;
+
+public class AlphabeticGeneratorTest extends TestCase {
+
+       final boolean NO_WRAP = false;
+       final boolean WRAP = true;
+       StringIdentifierGenerator generator;
+       
+       public void testNoWrapAndInitialValue() {
+
+               // @TODO: Split this test into more focused individual tests
+               
+               // All lowercase initial values
+               
+               generator = new AlphabeticGenerator(NO_WRAP, "a");
+               assertEquals("b", generator.nextStringIdentifier());
+               assertEquals("c", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "x");
+               assertEquals("y", generator.nextStringIdentifier());
+               assertEquals("z", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "aa");
+               assertEquals("ab", generator.nextStringIdentifier());
+               assertEquals("ac", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "ay");
+               assertEquals("az", generator.nextStringIdentifier());
+               assertEquals("ba", generator.nextStringIdentifier());
+               assertEquals("bb", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "zx");
+               assertEquals("zy", generator.nextStringIdentifier());
+               assertEquals("zz", generator.nextStringIdentifier());
+
+               // All uppercase initial values
+               
+               generator = new AlphabeticGenerator(NO_WRAP, "A");
+               assertEquals("B", generator.nextStringIdentifier());
+               assertEquals("C", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "X");
+               assertEquals("Y", generator.nextStringIdentifier());
+               assertEquals("Z", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "AA");
+               assertEquals("AB", generator.nextStringIdentifier());
+               assertEquals("AC", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "AY");
+               assertEquals("AZ", generator.nextStringIdentifier());
+               assertEquals("BA", generator.nextStringIdentifier());
+               assertEquals("BB", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(NO_WRAP, "ZX");
+               assertEquals("ZY", generator.nextStringIdentifier());
+               assertEquals("ZZ", generator.nextStringIdentifier());
+                       
+       }
+
+       public void testWrapAndInitialLowercaseValue() {
+       
+               generator = new AlphabeticGenerator(WRAP, "x");
+               assertEquals("y", generator.nextStringIdentifier());
+               assertEquals("z", generator.nextStringIdentifier());
+               assertEquals("a", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(WRAP, "zx");
+               assertEquals("zy", generator.nextStringIdentifier());
+               assertEquals("zz", generator.nextStringIdentifier());
+               assertEquals("aa", generator.nextStringIdentifier());
+               
+       }
+       
+       public void testOverflowWithNoWrapAndInitialLowercaseValue()
+               throws Exception {
+       
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, "zx");
+                       assertEquals("zy", generator.nextStringIdentifier());
+                       assertEquals("zz", generator.nextStringIdentifier());
+                       // Should throw IllegalStateException
+                       assertNotNull(generator.nextStringIdentifier());
+                       fail("Should have thrown IllegalStateException here");
+               } catch (IllegalStateException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+               
+       }
+
+       public void testWrapAndInitialUppercaseValue() {
+
+               generator = new AlphabeticGenerator(WRAP, "X");
+               assertEquals("Y", generator.nextStringIdentifier());
+               assertEquals("Z", generator.nextStringIdentifier());
+               assertEquals("A", generator.nextStringIdentifier());
+
+               generator = new AlphabeticGenerator(WRAP, "ZX");
+               assertEquals("ZY", generator.nextStringIdentifier());
+               assertEquals("ZZ", generator.nextStringIdentifier());
+               assertEquals("AA", generator.nextStringIdentifier());
+
+       }
+
+       public void testOverflowWithNoWrapAndInitialUppercaseValue() {
+       
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, "ZX");
+                       assertEquals("ZY", generator.nextStringIdentifier());
+                       assertEquals("ZZ", generator.nextStringIdentifier());
+                       // Should throw IllegalStateException
+                       assertNotNull(generator.nextStringIdentifier());
+                       fail("Should have thrown IllegalStateException here");
+               } catch (IllegalStateException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+               
+       }
+
+       public void testNonAlphabeticInitialValue() {
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, "&*432");
+                       fail("Should have thrown IllegalArgumentException here");
+               } catch (IllegalArgumentException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+       }
+
+       public void testNullInitialValue() {
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, null);
+                       fail("Should have thrown IllegalArgumentException here");
+               } catch (IllegalArgumentException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+       }
+
+       public void testEmptyStringInitialValue() {
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, "");
+                       fail("Should have thrown IllegalArgumentException here");
+               } catch (IllegalArgumentException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+       }
+
+       public void testAllSpaceCharsInitialValue() {
+               try {
+                       generator = new AlphabeticGenerator(NO_WRAP, "  ");
+                       fail("Should have thrown IllegalArgumentException here");
+               } catch (IllegalArgumentException expected) {
+                       // This Exception should be thrown, and thus the test should pass.
+               }
+       }
+}
diff --git a/sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticSeriesIDPartTest.java b/sandbox/aron/id/src/test/java/org/collectionspace/services/id/AlphabeticSeriesIDPartTest.java
new file mode 100644 (file)
index 0000000..4237eba
--- /dev/null
@@ -0,0 +1,44 @@
+ /*    
+ * AlphabeticSeriesIDPartTest
+ *
+ * Test class for AlphabeticSeriesIDPart.
+ *
+ * Copyright 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ *
+ * @author $Author$
+ * @version $Revision$
+ * $Date$
+ */
+
+package org.collectionspace.services.id;
+
+import junit.framework.TestCase;
+
+public class AlphabeticSeriesIDPartTest extends TestCase {
+
+       AlphabeticSeriesIDPart part;
+       
+       public void testInitialValue() {
+
+               part = new AlphabeticSeriesIDPart("a");
+               assertEquals("a", part.nextIdentifier());
+               assertEquals("b", part.nextIdentifier());
+
+               part = new AlphabeticSeriesIDPart("x");
+               assertEquals("x", part.nextIdentifier());
+               assertEquals("y", part.nextIdentifier());
+               assertEquals("z", part.nextIdentifier());
+               part.reset();
+               assertEquals("x", part.nextIdentifier());
+                       
+       }
+       
+       // Add tests of boundary conditions, exceptions ...
+}
diff --git a/sandbox/aron/id/third-party/commons-id-1.0-SNAPSHOT.jar b/sandbox/aron/id/third-party/commons-id-1.0-SNAPSHOT.jar
new file mode 100644 (file)
index 0000000..f60f41a
Binary files /dev/null and b/sandbox/aron/id/third-party/commons-id-1.0-SNAPSHOT.jar differ
diff --git a/sandbox/aron/id/third-party/install-third-party.sh b/sandbox/aron/id/third-party/install-third-party.sh
new file mode 100644 (file)
index 0000000..4eca6cc
--- /dev/null
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+mvn install:install-file \
+       -Dfile=./commons-id-1.0-SNAPSHOT.jar \
+       -DgroupId=org.apache.commons \
+  -DartifactId=commons-id \
+  -Dversion=1.0-SNAPSHOT \
+  -Dpackaging=jar