From 29d15f0b9f71cace1b5579f5ba7b48d40b26cb58 Mon Sep 17 00:00:00 2001 From: Aron Roberts Date: Wed, 24 Jun 2009 15:29:44 +0000 Subject: [PATCH] NOJIRA Some groundwork for matching on supplied partial IDs. --- .../services/id/AlphabeticIDGenerator.java | 48 ++++---- .../services/id/IDPattern.java | 108 +++++++++++++++++- .../services/id/NumericIDGenerator.java | 12 +- .../services/id/NumericIDPart.java | 8 +- .../services/id/IDPatternTest.java | 68 +++++++++++ 5 files changed, 213 insertions(+), 31 deletions(-) diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticIDGenerator.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticIDGenerator.java index b19690fee..b34ea4f43 100644 --- a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticIDGenerator.java +++ b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/AlphabeticIDGenerator.java @@ -37,7 +37,7 @@ // 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, +// Note also that, if the goal is to cycle through a sequence 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. @@ -67,8 +67,10 @@ public class AlphabeticIDGenerator implements IDGenerator { private Vector initialValue = new Vector(); private Vector currentValue = new Vector(); + // Constructor using defaults for character sequence and initial value. + // // If no start and end characters are provided for the alphabetic character - // sequence, default to an 'a-z' series, representing the lowercase alphabetic + // sequence, default to an 'a-z' sequence, representing the lowercase alphabetic // characters in the USASCII character set (within Java's internal // Unicode UTF-16 representation). // @@ -79,8 +81,10 @@ public class AlphabeticIDGenerator implements IDGenerator { } + // Constructor using defaults for character sequence. + // // If no start and end characters are provided for the alphabetic character - // sequence, default to an 'a-z' series, representing the lowercase alphabetic + // sequence, default to an 'a-z' sequence, representing the lowercase alphabetic // characters in the USASCII character set (within Java's internal // Unicode UTF-16 representation). public AlphabeticIDGenerator(String initial) throws IllegalArgumentException { @@ -89,18 +93,19 @@ public class AlphabeticIDGenerator implements IDGenerator { } - public AlphabeticIDGenerator(String seriesStart, String seriesEnd, String initial) + // Constructor. + public AlphabeticIDGenerator(String sequenceStart, String sequenceEnd, String initial) throws IllegalArgumentException { - // Validate and store the start character in the alphabetic series. + // Validate and store the start character in the character sequence. - if (seriesStart == null || seriesStart.equals("")) { + if (sequenceStart == null || sequenceStart.equals("")) { throw new IllegalArgumentException( - "Start character in the alphabetic series must not be null or empty"); + "Start character in the character sequence must not be null or empty"); } - if (seriesStart.length() == 1) { - this.startChar = seriesStart.charAt(0); + if (sequenceStart.length() == 1) { + this.startChar = sequenceStart.charAt(0); } else if (false) { // Handle representations of Unicode code points here } else { @@ -109,15 +114,15 @@ public class AlphabeticIDGenerator implements IDGenerator { // "Start character must be one character in length or a Unicode value such as '\u0000'"); } - // Validate and store the end character in the alphabetic series. + // Validate and store the end character in the character sequence. - if (seriesEnd == null || seriesEnd.equals("")) { + if (sequenceEnd == null || sequenceEnd.equals("")) { throw new IllegalArgumentException( - "End character in the alphabetic series must not be null or empty"); + "End character in the character sequence must not be null or empty"); } - if (seriesEnd.length() == 1) { - this.endChar = seriesEnd.charAt(0); + if (sequenceEnd.length() == 1) { + this.endChar = sequenceEnd.charAt(0); } else if (false) { // Handle representations of Unicode code points here } else { @@ -128,7 +133,7 @@ public class AlphabeticIDGenerator implements IDGenerator { if (this.endChar <= this.startChar) { throw new IllegalArgumentException( - "End (last) character in the alphabetic series must be greater than the start character"); + "End (last) character in the character sequence must be greater than the start character"); } // Validate and store the initial value of this identifier. @@ -141,7 +146,7 @@ public class AlphabeticIDGenerator implements IDGenerator { // Store the chars in the initial value as Characters in a Vector, // validating each character to identify whether it falls within - // the provided series. + // the provided sequence. // // (Since we're performing casts from char to Character, we can't just // use Arrays.asList() to copy the initial array to a Vector.) @@ -149,12 +154,11 @@ public class AlphabeticIDGenerator implements IDGenerator { char ch; 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. + // If the character falls within the provided sequence, copy it to the Vector. ch = chars[i]; if (ch >= this.startChar && ch <= this.endChar) { this.initialValue.add(new Character(ch)); - // Otherwise, we've detected a character not in the series. + // Otherwise, we've detected a character not in the sequence. } else { throw new IllegalArgumentException("character " + "\'" + ch + "\'" + " is not valid"); } @@ -195,7 +199,7 @@ public class AlphabeticIDGenerator implements IDGenerator { // Store the chars in the value as Characters in a Vector, // validating each character to identify whether it falls within - // the provided series. + // the provided sequence. // // (Since we're performing casts from char to Character, we can't just // use Arrays.asList() to copy the initial array to a Vector.) @@ -209,7 +213,7 @@ public class AlphabeticIDGenerator implements IDGenerator { 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. + // Otherwise, we've detected a character not in the sequence. } else { throw new IllegalArgumentException("character " + "\'" + ch + "\'" + " is not valid"); } @@ -220,7 +224,7 @@ public class AlphabeticIDGenerator implements IDGenerator { this.currentValue = new Vector(v); } - // Returns the next alphabetic ID in the series. + // Returns the next alphabetic ID in the sequence. // // Currently, the number of characters auto-expands as the // value of the most significant character rolls over. diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPattern.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPattern.java index cd20e8d0c..f927a0034 100644 --- a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPattern.java +++ b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/IDPattern.java @@ -60,22 +60,115 @@ public class IDPattern { return sb.toString(); } + // Returns the current value of this ID, given a + // supplied ID that partly matches the pattern. + // + // @TODO: Throws IllegalArgumentException + public synchronized String getCurrentID(String value) { + + if (value == null) return value; + + // Try ever-larger stem matches against the supplied value, + // by incrementally appending each part's regex, until no + // (more) matches are found. + // + // In so doing, build a subset of this IDPattern's regex + // that fully matches the supplied value. + Pattern pattern = null; + Matcher matcher = null; + int matchedParts = 0; + StringBuffer regexToTry = new StringBuffer(); + StringBuffer regex = new StringBuffer(); + for (IDPart partToTryMatching : this.parts) { + regexToTry.append(partToTryMatching.getRegex()); + pattern = Pattern.compile(regexToTry.toString()); + matcher = pattern.matcher(value); + // If a stem match was found on the current regex, + // store a count of matched IDParts and the regex pattern + // that has matched to this point. + if (matcher.lookingAt()) { + matchedParts++; + regex.append(partToTryMatching.getRegex()); + // Otherwise, exit the loop. + } else { + break; + } + } + + // If the supplied ID doesn't entirely match the pattern, + // return the supplied ID as the next ID. + // + // @TODO: We may wish to handle this differently, + // such as by throwing an Exception. + if (matchedParts == 0) { + // return value; + return "foo1"; + } + + pattern = Pattern.compile(regex.toString()); + matcher = pattern.matcher(value); + + // If the supplied ID doesn't entirely match the pattern, + // return the supplied ID as the next ID. + // + // @TODO: We may wish to handle this differently, + // such as by throwing an Exception. + if (! matcher.matches()) { + // return value; + return "foo2"; + } + + // Temporary for debugging + return regex.toString(); + +/* + // Otherwise, if the supplied ID partly 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 <= matchedParts; i++) { + currentPart = this.parts.get(i - 1); + currentPart.setCurrentID(matcher.group(i)); + } + + // Obtain the initial value of the next IDPart. + int nextPartNum = matchedParts - 1; + this.parts.get(nextPartNum).getInitialID(); + + // Then call the getCurrentID() method on each of the + // supplied IDParts, as well as on the additional + // IDPart whose current value was just obtained. + StringBuffer sb = new StringBuffer(); + IDPart part = null; + for (int i = 1; i <= matchedParts - 1; i++) { + sb.append(part.getCurrentID()); + } + + return sb.toString(); +*/ + + } + // 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(); + int lastPartNum = this.parts.size() - 1; + this.parts.get(lastPartNum).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 @@ -90,7 +183,7 @@ public class IDPattern { Matcher matcher = pattern.matcher(value); // If the supplied ID doesn't entirely match the pattern, - // return that same ID as the next ID. + // return the supplied ID as the next ID. // // @TODO: We may wish to handle this differently, // such as by throwing an Exception. @@ -100,7 +193,7 @@ public class IDPattern { // 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. + // each of the pattern's IDParts. IDPart currentPart; for (int i = 1; i <= (matcher.groupCount() - 1); i++) { currentPart = this.parts.get(i - 1); @@ -114,14 +207,17 @@ public class IDPattern { // // @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(); + int lastPartNum = this.parts.size() - 1; + this.parts.get(lastPartNum).getNextID(); + // Then call the getCurrentID() method on all of the IDParts StringBuffer sb = new StringBuffer(); for (IDPart part : this.parts) { sb.append(part.getCurrentID()); } + return sb.toString(); + } // Validates a provided ID against the pattern. diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDGenerator.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDGenerator.java index 12c016e30..69b12e2cf 100644 --- a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDGenerator.java +++ b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDGenerator.java @@ -31,13 +31,21 @@ 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; + final static private int DEFAULT_INITIAL_VALUE = 1; + private long initialValue = DEFAULT_INITIAL_VALUE; + private long currentValue = DEFAULT_INITIAL_VALUE; + // Constructor using defaults for initial value and maximum length. + public NumericIDGenerator() throws IllegalArgumentException { + this(Integer.toString(DEFAULT_INITIAL_VALUE), Integer.toString(DEFAULT_MAX_LENGTH)); + } + + // Constructor using default maximum length. public NumericIDGenerator(String initialValue) throws IllegalArgumentException { this(initialValue, Integer.toString(DEFAULT_MAX_LENGTH)); } + // Constructor. public NumericIDGenerator(String initialValue, String maxLength) throws IllegalArgumentException { diff --git a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDPart.java b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDPart.java index 0ec10d5e9..78977e85f 100644 --- a/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDPart.java +++ b/sandbox/aron/id/src/main/java/org/collectionspace/services/id/NumericIDPart.java @@ -24,11 +24,17 @@ package org.collectionspace.services.id; public class NumericIDPart extends IDPart { + public NumericIDPart() throws IllegalArgumentException { + super(new NumericIDGenerator()); + }; + + // Store the appropriate Numeric ID generator and the base value for this part. public NumericIDPart(String baseVal) throws IllegalArgumentException { - // Store the appropriate Numeric ID generator and the base value for this part. super(new NumericIDGenerator(baseVal)); }; + // Store the appropriate Numeric ID generator, and the base value + // and maximum length for this part. public NumericIDPart(String baseVal, String maxLength) throws IllegalArgumentException { super(new NumericIDGenerator(baseVal, maxLength)); }; diff --git a/sandbox/aron/id/src/test/java/org/collectionspace/services/id/IDPatternTest.java b/sandbox/aron/id/src/test/java/org/collectionspace/services/id/IDPatternTest.java index 3a640ffea..3ed1a7fe5 100644 --- a/sandbox/aron/id/src/test/java/org/collectionspace/services/id/IDPatternTest.java +++ b/sandbox/aron/id/src/test/java/org/collectionspace/services/id/IDPatternTest.java @@ -56,6 +56,74 @@ public class IDPatternTest extends TestCase { } + public void testCurrentIDWithPartialSuppliedID() { + + // @TODO: Temporary for testing: ascertain regex patterns + + pattern = new IDPattern(); + pattern.add(new StringIDPart("E")); + pattern.add(new NumericIDPart("1")); + assertEquals("(E)", pattern.getCurrentID("E")); + + // assertEquals("E1", pattern.getCurrentID("E")); + // assertEquals("E2.", pattern.getNextID()); + + pattern = new IDPattern(); + pattern.add(new YearIDPart()); + pattern.add(new StringIDPart(".")); + assertEquals("(\\d{4})", pattern.getCurrentID("2009")); + + // assertEquals("2009.", pattern.getCurrentID("2009")); + // assertEquals("2009.", pattern.getNextID()); + // assertEquals("2010.", pattern.getCurrentID("2010")); + // assertEquals("2010.", pattern.getNextID()); + + pattern = new IDPattern(); + pattern.add(new YearIDPart()); + pattern.add(new StringIDPart(".")); + pattern.add(new NumericIDPart("1")); + assertEquals("(\\d{4})(\\.)", pattern.getCurrentID("2009.")); + + // assertEquals("2009.1", pattern.getCurrentID("2009.")); + // assertEquals("2009.2", pattern.getNextID()); + + pattern = new IDPattern(); + pattern.add(new YearIDPart()); + pattern.add(new StringIDPart(".")); + pattern.add(new NumericIDPart("55")); + assertEquals("(\\d{4})(\\.)", pattern.getCurrentID("2010.")); + + // assertEquals("2010.55", pattern.getCurrentID("2010.")); + // assertEquals("2010.56", pattern.getNextID()); + + pattern = new IDPattern(); + pattern.add(new YearIDPart("2009")); + pattern.add(new StringIDPart(".")); + assertEquals("(\\d{4})(\\.)", pattern.getCurrentID("2009.")); + + // assertEquals("2009.1", pattern.getCurrentID("2009.")); + // assertEquals("2009.2", pattern.getNextID()); + + 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("(\\d{4})(\\.)(\\d{1,6})(-)", pattern.getCurrentID("2009.1-")); + + // assertEquals("2009.1-a", pattern.getNextID("2009.1-")); + // assertEquals("2009.1-b", pattern.getNextID(); + // assertEquals("2009.3-a", pattern.getNextID("2009.3-")); + + } + + public void testCurrentIDWithFullSuppliedID() { + + // @TODO TBA + + } + public void testNextID() { pattern = new IDPattern(); -- 2.47.3