]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
NOJIRA Added support for getting a next ID, given a supplied instance of an ID matchi...
authorAron Roberts <aron@socrates.berkeley.edu>
Wed, 24 Jun 2009 03:48:33 +0000 (03:48 +0000)
committerAron Roberts <aron@socrates.berkeley.edu>
Wed, 24 Jun 2009 03:48:33 +0000 (03:48 +0000)
sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticIDGenerator.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDGenerator.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPart.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPattern.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDGenerator.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/StringIDGenerator.java
sandbox/aron/id/src/main/java/org/collectionspace/services/id/YearIDGenerator.java
sandbox/aron/id/src/test/java/org/collectionspace/services/id/IDPatternTest.java

index 88b046f1e26930e19e6a21f3168f7d8439f8d18a..b19690feedfe52de89d90fe623c5093b4017501a 100644 (file)
@@ -23,8 +23,8 @@
 // generated IDs can grow, likely as an additional parameter to be
 // passed to a constructor, with a default value hard-coded in the class.
 
-// @TODO: Handle escaped characters or sequences which represent Unicode code points,
-// both in the start and end characters of the sequence, and in the initial value.
+// @TODO: Consider handling escaped characters or sequences which represent Unicode
+// code points, both in the start and end characters of the sequence, and in the initial value.
 // (Example: '\u0072' for the USASCII 'r' character; see
 // http://www.fileformat.info/info/unicode/char/0072/index.htm)
 //
 // http://www.velocityreviews.com/forums/t367758-unescaping-unicode-code-points-in-a-java-string.html
 // We might also look into the (protected) source code for java.util.Properties.load()
 // which reads escaped Unicode values.
+//
+// Note also that, if the goal is to cycle through a series of alphabetic identifiers,
+// such as the sequence of characters used in a particular human language, it may or may not
+// be the case that any contiguous Unicode code point sequence reflects such a character sequence.
 
 // NOTE: This class currently hard-codes the assumption that the values in
 // alphabetic identifiers are ordered in significance from left-to-right;
@@ -143,7 +147,7 @@ public class AlphabeticIDGenerator implements IDGenerator {
          // use Arrays.asList() to copy the initial array to a Vector.)
                char[] chars = initial.toCharArray();
                char ch;
-               for (int i=0; i < chars.length; i++) {
+               for (int i = 0; i < chars.length; i++) {
 
       // If the character falls within the range bounded by the start and end
       // characters, copy it to the Vector.
@@ -176,6 +180,45 @@ public class AlphabeticIDGenerator implements IDGenerator {
        public synchronized String getCurrentID() {
                return getIDString(this.currentValue);
        }
+
+  // Sets the current value.
+       public synchronized void setCurrentID(String value) throws IllegalArgumentException {
+       
+         // @TODO Much of this code is copied from the main constructor,
+         // and may be ripe for refactoring.
+         
+               if (value == null || value.equals("")) {
+                       throw new IllegalArgumentException("Initial value must not be null or empty");
+               }
+               
+               // @TODO: Add a check for maximum length of the value here.
+       
+         // Store the chars in the value as Characters in a Vector,
+         // validating each character to identify whether it falls within
+         // the provided series.
+         //
+         // (Since we're performing casts from char to Character, we can't just
+         // use Arrays.asList() to copy the initial array to a Vector.)
+               char[] chars = value.toCharArray();
+               char ch;
+               Vector v = new Vector<Character>();
+               for (int i = 0; i < chars.length; i++) {
+
+      // If the character falls within the range bounded by the start and end
+      // characters, copy it to the Vector.
+      ch = chars[i];
+                       if (ch >= this.startChar && ch <= this.endChar) {
+                         v.add(new Character(ch));
+      // Otherwise, we've detected a character not in the series.
+                       } else {
+        throw new IllegalArgumentException("character " + "\'" + ch + "\'" + " is not valid");
+      }
+                 
+               }
+
+               // Set the current value.
+               this.currentValue = new Vector<Character>(v);
+       }
        
        // Returns the next alphabetic ID in the series.
        //
index 03b3f9bf29507bb678800e36c2011140fe8b6117..5b43709d2c5db7e350034f167f44d3fbe76feada 100644 (file)
@@ -29,6 +29,8 @@ public interface IDGenerator {
        public String getInitialID();
 
        public String getCurrentID();
+       
+       public void setCurrentID(String value);
 
        public String getNextID();
 
index 48b4f086ce655827af58ee7d24f3ec8b072a6a05..ffabe304c72e54c51949052bad662d2565f7ad41 100644 (file)
@@ -55,6 +55,11 @@ public abstract class IDPart {
                return generator.getCurrentID();
        }
 
+       // Sets the current value of this ID.
+       public synchronized void setCurrentID(String value) {
+               generator.setCurrentID(value);
+       }
+
        // Returns the next value of this ID.
        public synchronized String getNextID() throws IllegalStateException {
                return generator.getNextID();
index 4246c39fb7a5e5e38df68b1c9a172142535f0693..cd20e8d0cc9c95db01aa108b3e501f5922bb3f23 100644 (file)
@@ -18,6 +18,9 @@
 
 // @TODO: Add Javadoc comments
 
+// @TODO: Catch Exceptions thrown by IDPart, then
+// reflect this in the corresponding IDPatternTest class.
+
 package org.collectionspace.services.id;
 
 import java.util.Vector;
@@ -58,15 +61,63 @@ public class IDPattern {
        }
 
        // Returns the next value of this ID.
+       //
+       // @TODO: Throws IllegalArgumentException
        public synchronized String getNextID() {
+               // Obtain the last (least significant) IDPart,
+               // and call its getNextID() method, which will
+               // concurrently set the current value of that ID
+               // to the next ID.
+               int last = this.parts.size() - 1;
+               this.parts.get(last).getNextID();
+               // Then call the getCurrentID() method on all of the IDParts
                StringBuffer sb = new StringBuffer(MAX_ID_LENGTH);
+               for (IDPart part : this.parts) {
+                       sb.append(part.getCurrentID());
+               }
+               return sb.toString();
+       }
+
+       // Returns the next value of this ID, given a
+       // supplied ID that entirely matches the pattern.
+       //
+  // @TODO: Throws IllegalArgumentException
+       public synchronized String getNextID(String value) {
+
+         if (value == null) return value;
+       
+               Pattern pattern = Pattern.compile(getRegex());
+               Matcher matcher = pattern.matcher(value);
+               
+               // If the supplied ID doesn't entirely match the pattern,
+               // return that same ID as the next ID.
+               //
+               // @TODO: We may wish to handle this differently,
+               // such as by throwing an Exception.
+               if (! matcher.matches()) {
+                       return value;
+               }
+               
+               // Otherwise, if the supplied ID entirely matches the pattern,
+               // split the ID into its components and store those values in
+               // each of the pattern's IDparts.
+               IDPart currentPart;
+               for (int i = 1; i <= (matcher.groupCount() - 1); i++) {
+                 currentPart = this.parts.get(i - 1);
+      currentPart.setCurrentID(matcher.group(i));
+               }
+
                // Obtain the last (least significant) IDPart,
                // and call its getNextID() method, which will
                // concurrently set the current value of that ID
                // to the next ID.
+               //
+               // @TODO: This code is duplicated in getNextID(), above,
+               // and thus we may want to refactor this.
                int last = this.parts.size() - 1;
                this.parts.get(last).getNextID();
                // Then call the getCurrentID() method on all of the IDParts
+               StringBuffer sb = new StringBuffer();
                for (IDPart part : this.parts) {
                        sb.append(part.getCurrentID());
                }
@@ -74,8 +125,12 @@ public class IDPattern {
        }
 
        // Validates a provided ID against the pattern.
+       //
+       // @TODO May potentially throw at least one pattern-related exception.
        public synchronized boolean isValidID(String value) {
        
+         if (value == null) return false;
+       
                Pattern pattern = Pattern.compile(getRegex());
                Matcher matcher = pattern.matcher(value);
                if (matcher.matches()) {
index b8cad8bbe9bc44b470b6f8a6c2e83c46b85364f9..12c016e30e273a3fb147d6579312496a124b10c5 100644 (file)
@@ -73,6 +73,29 @@ public class NumericIDGenerator implements IDGenerator {
        public synchronized String getCurrentID() {
                return Long.toString(this.currentValue);
        }
+
+  // Sets the current value.
+       public synchronized void setCurrentID(String value) throws IllegalArgumentException {
+
+         // @TODO Much of this code is copied from the main constructor,
+         // and may be ripe for refactoring.
+               try {
+                       long l = Long.parseLong(value.trim());
+                       if ( l < 0 ) {
+                               throw new IllegalArgumentException("Initial ID value should be zero (0) or greater");
+                       }
+                       this.currentValue = l;
+                       this.initialValue = l;
+               } catch (NullPointerException e) {
+                       throw new IllegalArgumentException("ID value should not be null");
+               } catch (NumberFormatException e) {
+                       throw new IllegalArgumentException("ID value must be parseable as a number");
+               }
+               
+               // @TODO An expedient; we may need to check the String length of the
+               // provided ID and calculate a maximum length here.
+               this.maxLength = DEFAULT_MAX_LENGTH;
+       }
        
        public synchronized String getNextID() throws IllegalStateException {
                this.currentValue++;
index 02a3294373b40ad36a1ec16bf7fc0648e539b26a..04e8e64c699f8e6e77929894780e45a2d069b927 100644 (file)
@@ -53,6 +53,13 @@ public class StringIDGenerator implements IDGenerator {
        public synchronized String getCurrentID() {
                return this.currentValue;
        }
+
+       public synchronized void setCurrentID(String value) throws IllegalArgumentException {
+               if ( initialValue == null || initialValue == "") {
+                       throw new IllegalArgumentException("ID value must not be null or empty");
+               }
+               this.currentValue = value;
+       }
        
        public synchronized String getNextID() {
                return this.currentValue;
index c91fc7f851562d0beacffb7b96829da7204874b8..41f07f2f5abb76475c968a4cade469dd81c8ab35 100644 (file)
@@ -63,9 +63,8 @@ public class YearIDGenerator implements IDGenerator {
                        throw new IllegalArgumentException("Initial ID value must not be null or empty");
                }
                
-               // @TODO: Add regex-based validation here, by calling a
-               // to-be-added validate() method.  Consider implications
-               // for Internationalization when doing so.
+               // @TODO: Add regex-based validation here, by calling isValidID().
+               // Consider implications for Internationalization when doing so.
                
                this.initialValue = initialValue;
                this.currentValue = initialValue;
@@ -83,6 +82,23 @@ public class YearIDGenerator implements IDGenerator {
        public synchronized String getCurrentID() {
                return this.currentValue;
        }
+
+  // Sets the current value.
+       public synchronized void setCurrentID(String value) throws IllegalArgumentException {
+
+         // @TODO This code is copied from the main constructor,
+         // and thus there may be an opportunity for refactoring.
+
+               if ( value == null || value == "") {
+                       throw new IllegalArgumentException("ID value must not be null or empty");
+               }
+               
+               // @TODO: Add regex-based validation here, by calling isValidID().
+               // Consider implications for Internationalization when doing so.
+
+               this.currentValue = value;
+
+       }
        
        // @TODO: We'll need to decide what a "next" ID means in the context of:
        // - An initially supplied value.
index f83c522aeb9ca4f9d4efea90b891d42b69f8ec1f..3a640ffea6682176689cfa670c099cd615dec678 100644 (file)
@@ -93,6 +93,26 @@ public class IDPatternTest extends TestCase {
                assertEquals("2009.1-", pattern.getNextID());
 
        }
+
+       public void testNextIDWithSuppliedID() {
+       
+               pattern = new IDPattern();
+               pattern.add(new YearIDPart("2009"));
+               pattern.add(new StringIDPart("."));
+               pattern.add(new NumericIDPart("1"));
+               assertEquals("2009.2", pattern.getNextID("2009.1"));
+               assertEquals("2009.3", pattern.getNextID("2009.2"));
+
+               pattern = new IDPattern();
+               pattern.add(new YearIDPart("2009"));
+               pattern.add(new StringIDPart("."));
+               pattern.add(new NumericIDPart("1"));
+               pattern.add(new StringIDPart("-"));
+               pattern.add(new AlphabeticIDPart("a"));
+               assertEquals("2009.1-b", pattern.getNextID("2009.1-a"));
+               assertEquals("2009.3-c", pattern.getNextID("2009.3-b"));
+
+       }
        
        public void testEmptyPartsListCurrentID() {