From 1d2462bb4e2fe9c8c4a2fb9f9df0c7a5bc841339 Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Fri, 18 Sep 2009 23:05:16 +0000
Subject: [PATCH] Fix for issue 4226: PartialDateOrTimeMatchingRule doesn't do time matching
---
opends/tests/unit-tests-testng/src/server/org/opends/server/schema/TimeBasedMatchingRuleTest.java | 97 +++++++++--
opends/src/messages/messages/schema.properties | 25 ++
opends/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java | 324 ++++++++++++++++++++++-----------------
3 files changed, 279 insertions(+), 167 deletions(-)
diff --git a/opends/src/messages/messages/schema.properties b/opends/src/messages/messages/schema.properties
index 798246a..2fff3d5 100644
--- a/opends/src/messages/messages/schema.properties
+++ b/opends/src/messages/messages/schema.properties
@@ -966,11 +966,11 @@
,h(hour),d(day) and w(week)
MILD_WARN_ATTR_INVALID_PARTIAL_TIME_ASSERTION_FORMAT_295=The provided \
value "%s" could not be parsed as a valid assertion value because the \
- character '%c' is not allowed. The acceptable values are DD (date),MM(month) \
- and YYYY(year)
-MILD_WARN_ATTR_MISSING_CHAR_PARTIAL_TIME_ASSERTION_FORMAT_296=The provided \
- value "%s" could not be parsed as a valid assertion value because an invalid \
- character '%c' is found instead of '%c' at position %d
+ character '%c' is not allowed. The acceptable values are s(second), \
+ m (minute), h (hour), D (date), M(month) and Y(year)
+MILD_WARN_ATTR_INVALID_SECOND_ASSERTION_FORMAT_296=The provided \
+ value "%s" could not be parsed as a valid assertion value because "%d" is not \
+ a valid second specification
MILD_WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT_297=The provided \
value "%s" could not be parsed as a valid assertion value because "%d" is not \
a valid date specification
@@ -1015,3 +1015,18 @@
MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_DUPLICATE_VALUE_311=The provided value \
"%s" cannot be parsed as an enumeration syntax because it contains a \
duplicate value "%s" at position %d
+MILD_WARN_ATTR_INVALID_MINUTE_ASSERTION_FORMAT_312=The provided \
+ value "%s" could not be parsed as a valid assertion value because "%d" is not \
+ a valid minute specification
+MILD_WARN_ATTR_INVALID_HOUR_ASSERTION_FORMAT_313=The provided \
+ value "%s" could not be parsed as a valid assertion value because "%d" is not \
+ a valid hour specification
+MILD_WARN_ATTR_DUPLICATE_SECOND_ASSERTION_FORMAT_314=The provided \
+ value "%s" could not be parsed as a valid assertion value because there is \
+ conflicting value "%d" for s(Second) specification
+MILD_WARN_ATTR_DUPLICATE_MINUTE_ASSERTION_FORMAT_315=The provided \
+ value "%s" could not be parsed as a valid assertion value because there is \
+ conflicting value "%d" for m(Minute) specification
+MILD_WARN_ATTR_DUPLICATE_HOUR_ASSERTION_FORMAT_316=The provided \
+ value "%s" could not be parsed as a valid assertion value because there is \
+ conflicting value "%d" for h(Hour) specification
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java b/opends/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
index 70d5486..489f64e 100644
--- a/opends/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
+++ b/opends/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
@@ -53,6 +53,7 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteSequence;
import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.IndexConfig;
@@ -95,42 +96,23 @@
TimeZone.getTimeZone(TIME_ZONE_UTC);
- //Constants for months.
- private static final byte[] JAN = {'j','a','n' };
+ //Constants for generating keys.
+ private static final char SECOND = 's';
- private static final byte[] FEB = {'f','e','b'};
+ private static final char MINUTE = 'm';
- private static final byte[] MAR = {'m','a','r'};
+ private static final char HOUR = 'h';
- private static final byte[] APR = {'a','p','r'};
+ private static final char MONTH = 'M';
- private static final byte[] MAY = {'m','a','y'};
+ private static final char DATE = 'D';
- private static final byte[] JUN = {'j','u','n'};
-
-
- private static final byte[] JUL = {'j','u','l'};
-
-
- private static final byte[] AUG = {'a','u','g'};
-
-
- private static final byte[] SEP = {'s','e','p'};
-
-
- private static final byte[] OCT = {'o','c','t'};
-
-
- private static final byte[] NOV = {'n','o','v'};
-
-
- private static final byte[] DEC = {'d','e','c'};
-
+ private static final char YEAR = 'Y';
/**
@@ -793,17 +775,23 @@
{
/**
An assertion value may contain one or all of the following:
- DD = day
- MM = month
- YYYY = year
+ D = day
+ M = month
+ Y = year
+ h = hour
+ m = month
+ s = second
- An example assertion is OID:=04MM. In this example we are
+ An example assertion is OID:=04M. In this example we are
searching for entries corresponding to month of april.
Use this method to parse, validate and normalize the assertion value
into a format to be recognized by the compare routine. The normalized
- value is actually the format of : DDMMYYYY.
+ value is actually the format of : smhDMY.
*/
+ int second = -1;
+ int minute = -1;
+ int hour = -1;
int date = 0;
int year = 0;
int number = 0;
@@ -863,16 +851,44 @@
Message message = null;
switch(value.byteAt(index))
{
- case 'D':
- if(!(index < length-1) || value.byteAt(index+1) !='D')
+ case 's':
+ if(second >0)
{
- //the acceptable format is 'DD'.
- message =
- WARN_ATTR_MISSING_CHAR_PARTIAL_TIME_ASSERTION_FORMAT.
- get(value.toString(),
- (char)value.byteAt(index),'D',index+1);
+ message =
+ WARN_ATTR_DUPLICATE_SECOND_ASSERTION_FORMAT.get(
+ value.toString(),date);
}
- else if(number == 0)
+ else
+ {
+ second = number;
+ }
+ break;
+ case 'm':
+ if(minute >0)
+ {
+ message =
+ WARN_ATTR_DUPLICATE_MINUTE_ASSERTION_FORMAT.get(
+ value.toString(),date);
+ }
+ else
+ {
+ minute = number;
+ }
+ break;
+ case 'h':
+ if(hour >0)
+ {
+ message =
+ WARN_ATTR_DUPLICATE_HOUR_ASSERTION_FORMAT.get(
+ value.toString(),date);
+ }
+ else
+ {
+ hour = number;
+ }
+ break;
+ case 'D':
+ if(number == 0)
{
message =
WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT.get(
@@ -887,19 +903,10 @@
else
{
date = number;
- index++;
}
break;
case 'M':
- if(!(index < length-1) || value.byteAt(index+1)!='M')
- {
- //the acceptable value is 'MM'.
- message =
- WARN_ATTR_MISSING_CHAR_PARTIAL_TIME_ASSERTION_FORMAT.
- get(value.toString(),
- (char)value.byteAt(index),'M',index+1);
- }
- else if(number == 0)
+ if(number == 0)
{
message =
WARN_ATTR_INVALID_MONTH_ASSERTION_FORMAT.
@@ -914,48 +921,23 @@
else
{
month = number;
- index++;
}
break;
case 'Y':
- if(!(index < length-3))
+ if(number == 0)
{
- //the acceptable value is 'YYYY".
message =
- WARN_ATTR_MISSING_YEAR_PARTIAL_TIME_ASSERTION_FORMAT.
- get(value.toString());
+ WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT.
+ get(value.toString(),number);
+ }
+ else if(year >0)
+ {
+ message = WARN_ATTR_DUPLICATE_YEAR_ASSERTION_FORMAT.
+ get(value.toString(),year);
}
else
{
-yearLoop: for(int i=index;i<index+3;i++)
- {
- if(value.byteAt(i) !='Y')
- {
- message =
- WARN_ATTR_MISSING_CHAR_PARTIAL_TIME_ASSERTION_FORMAT.
- get(value.toString(),(char)value.byteAt(i),'Y',i);
- break yearLoop;
- }
- }
- if(message == null)
- {
- if(number == 0)
- {
- message =
- WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT.
- get(value.toString(),number);
- }
- else if(year >0)
- {
- message = WARN_ATTR_DUPLICATE_YEAR_ASSERTION_FORMAT.
- get(value.toString(),year);
- }
- else
- {
- year = number;
- index+=3;
- }
- }
+ year = number;
}
break;
default:
@@ -976,7 +958,7 @@
}
}
- //Validate year, month and date in that order.
+ //Validate year, month , date , hour, minute and second in that order.
if(year < 0)
{
//A future date is allowed.
@@ -1072,11 +1054,44 @@
ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
}
+ if(!(hour >=-1 && hour <=23))
+ {
+ Message message =
+ WARN_ATTR_INVALID_HOUR_ASSERTION_FORMAT.
+ get(value.toString(),date);
+ logError(message);
+ throw new DirectoryException(
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
+ }
+
+ if(!(minute >=-1 && minute <=59))
+ {
+ Message message =
+ WARN_ATTR_INVALID_MINUTE_ASSERTION_FORMAT.
+ get(value.toString(),date);
+ logError(message);
+ throw new DirectoryException(
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
+ }
+
+ if(!(second >=-1 && second <=60)) //Consider leap seconds.
+ {
+ Message message =
+ WARN_ATTR_INVALID_SECOND_ASSERTION_FORMAT.
+ get(value.toString(),date);
+ logError(message);
+ throw new DirectoryException(
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
+ }
+
/**
* Since we reached here we have a valid assertion value. Construct
- * a normalized value in the order: DATE MONTH YEAR.
+ * a normalized value in the order: SECOND MINUTE HOUR DATE MONTH YEAR.
*/
- ByteBuffer bb = ByteBuffer.allocate(3*4);
+ ByteBuffer bb = ByteBuffer.allocate(6*4);
+ bb.putInt(second);
+ bb.putInt(minute);
+ bb.putInt(hour);
bb.putInt(date);
bb.putInt(month);
bb.putInt(year);
@@ -1097,15 +1112,37 @@
GregorianCalendar cal = new GregorianCalendar(TIME_ZONE_UTC_OBJ);
cal.setLenient(false);
cal.setTimeInMillis(timeInMS);
+ int second = cal.get(Calendar.SECOND);
+ int minute = cal.get(Calendar.MINUTE);
+ int hour = cal.get(Calendar.HOUR_OF_DAY);
int date = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
+
//Build the information from the assertion value.
ByteBuffer bb = ByteBuffer.wrap(assertionValue.toByteArray());
- int assertDate = bb.getInt(0);
- int assertMonth = bb.getInt(4);
- int assertYear = bb.getInt(8);
+ int assertSecond = bb.getInt(0);
+ int assertMinute = bb.getInt(4);
+ int assertHour = bb.getInt(8);
+ int assertDate = bb.getInt(12);
+ int assertMonth = bb.getInt(16);
+ int assertYear = bb.getInt(20);
+
+ if(assertSecond != -1 && assertSecond !=second)
+ {
+ return ConditionResult.FALSE;
+ }
+
+ if(assertMinute !=-1 && assertMinute !=minute)
+ {
+ return ConditionResult.FALSE;
+ }
+
+ if(assertHour !=-1 && assertHour !=hour)
+ {
+ return ConditionResult.FALSE;
+ }
//All the non-zero values should match.
if(assertDate !=0 && assertDate != date)
@@ -1152,30 +1189,54 @@
byte[] arr = normalizeAssertionValue(assertionValue).toByteArray();
ByteBuffer bb = ByteBuffer.wrap(arr);
- int assertDate = bb.getInt(0);
- int assertMonth = bb.getInt(4);
- int assertYear = bb.getInt(8);
+ int assertSecond = bb.getInt(0);
+ int assertMinute = bb.getInt(4);
+ int assertHour = bb.getInt(8);
+ int assertDate = bb.getInt(12);
+ int assertMonth = bb.getInt(16);
+ int assertYear = bb.getInt(20);
List<T> queries = new ArrayList<T>();
+ if(assertSecond >= 0)
+ {
+ queries.add(factory.createExactMatchQuery(
+ indexer.getExtensibleIndexID(),
+ getKey(assertSecond,SECOND)));
+ }
+
+ if(assertMinute >=0)
+ {
+ queries.add(factory.createExactMatchQuery(
+ indexer.getExtensibleIndexID(),
+ getKey(assertMinute,MINUTE)));
+ }
+
+ if(assertHour >=0)
+ {
+ queries.add(factory.createExactMatchQuery(
+ indexer.getExtensibleIndexID(),
+ getKey(assertHour,HOUR)));
+ }
+
if(assertDate >0)
{
queries.add(factory.createExactMatchQuery(
indexer.getExtensibleIndexID(),
- ByteString.valueOf(assertDate)));
+ getKey(assertDate,DATE)));
}
if(assertMonth >=0)
{
queries.add(factory.createExactMatchQuery(
indexer.getExtensibleIndexID(),
- ByteString.wrap(getMonthKey(assertMonth))));
+ getKey(assertMonth,MONTH)));
}
if(assertYear > 0)
{
queries.add(factory.createExactMatchQuery(
indexer.getExtensibleIndexID(),
- ByteString.valueOf(assertYear)));
+ getKey(assertYear,YEAR)));
}
return factory.createIntersectionQuery(queries);
}
@@ -1207,76 +1268,53 @@
//Build the information from the attribute value.
GregorianCalendar cal = new GregorianCalendar(TIME_ZONE_UTC_OBJ);
cal.setTimeInMillis(timeInMS);
+ int second = cal.get(Calendar.SECOND);
+ int minute = cal.get(Calendar.MINUTE);
+ int hour = cal.get(Calendar.HOUR_OF_DAY);
int date = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
+ if (second >=0)
+ {
+ keys.add(getKey(second,SECOND).toByteArray());
+ }
+
+ if(minute >=0)
+ {
+ keys.add(getKey(minute,MINUTE).toByteArray());
+ }
+
+ if(hour >=0)
+ {
+ keys.add(getKey(hour,HOUR).toByteArray());
+ }
//Insert date.
if(date > 0)
{
- keys.add(ByteString.valueOf(date).toByteArray());
+ keys.add(getKey(date,DATE).toByteArray());
}
//Insert month.
if(month >=0)
{
- keys.add(getMonthKey(month));
+ keys.add(getKey(month,MONTH).toByteArray());
}
if(year > 0)
{
- keys.add(ByteString.valueOf(year).toByteArray());
+ keys.add(getKey(year,YEAR).toByteArray());
}
}
- //Returns a byte array of for the corresponding month.
- private byte[] getMonthKey(int month)
+ private ByteString getKey(int value, char type)
{
- byte[] key = null;
- switch(month)
- {
- case Calendar.JANUARY:
- key = JAN;
- break;
- case Calendar.FEBRUARY:
- key = FEB;
- break;
- case Calendar.MARCH:
- key = MAR;
- break;
- case Calendar.APRIL:
- key = APR;
- break;
- case Calendar.MAY:
- key = MAY;
- break;
- case Calendar.JUNE:
- key = JUN;
- break;
- case Calendar.JULY:
- key = JUL;
- break;
- case Calendar.AUGUST:
- key = AUG;
- break;
- case Calendar.SEPTEMBER:
- key = SEP;
- break;
- case Calendar.OCTOBER:
- key = OCT;
- break;
- case Calendar.NOVEMBER:
- key = NOV;
- break;
- case Calendar.DECEMBER:
- key = DEC;
- break;
- default:
- key = new byte[0];
- }
- return key;
+ ByteStringBuilder builder = new ByteStringBuilder();
+ builder.append(type);
+ builder.append(value);
+ return builder.toByteString();
}
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/TimeBasedMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/TimeBasedMatchingRuleTest.java
index 633cafb..e2e8812 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/TimeBasedMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/TimeBasedMatchingRuleTest.java
@@ -42,6 +42,7 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.types.ByteString;
+import org.opends.server.types.ConditionResult;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
@@ -285,7 +286,7 @@
* Test to search using the partial date and time matching rule for an assertion value.
*/
@Test()
- public void testPartialDateNTimeMatchingRule() throws Exception
+ public void testPartialDateNTimeMatchingRuleUsingSearch() throws Exception
{
try
{
@@ -293,7 +294,7 @@
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
int month = cal.get(Calendar.MONTH)+1; //month starts from 0 in the Calendar.
- String assertion = cal.get(Calendar.DATE)+"DD"+month+"MM";
+ String assertion = cal.get(Calendar.DATE)+"D"+month+"M";
InternalSearchOperation searchOperation =
new InternalSearchOperation(
@@ -322,6 +323,21 @@
}
+ /**
+ * Test to match the attribute and the assertion values using a partial date and time
+ * matching rule.
+ */
+ @Test(dataProvider="partialDateTimeValues")
+ public void testPartialDateNTimeMatch(long attributeValue,String assertionValue) throws Exception
+ {
+ MatchingRule partialTimeRule = DirectoryServer.getMatchingRule(
+ EXT_PARTIAL_DATE_TIME_NAME.toLowerCase());
+ ByteString str = partialTimeRule.normalizeAssertionValue(ByteString.valueOf(assertionValue));
+ assertTrue(partialTimeRule.valuesMatch(ByteString.valueOf(attributeValue), str) ==
+ ConditionResult.TRUE);
+ }
+
+
/**
* Tests the assertion syntax of the relative time matching rules.
@@ -355,7 +371,7 @@
/**
* Tests the assertion syntax of the partial date and time matching rules.
*/
- @Test(dataProvider= "partialDateTimeValues")
+ @Test(dataProvider= "partialDateTimeSyntaxes")
public void testPartialDateTimeMatchingRuleAssertionSyntax(String assertion,boolean isValid)
{
MatchingRule partialDTRule =
@@ -403,14 +419,45 @@
}
-
/**
- * Generates data for testing partial date and time assertion syntax.
+ * Generates the data for testing partial time date and time values.
*/
@DataProvider(name="partialDateTimeValues")
private Object[][] createPartialDateTimeValues()
{
+ GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ c.setLenient(false);
+ c.clear();
+ c.set(Calendar.HOUR_OF_DAY,23);
+ c.set(Calendar.MINUTE,0);
+ c.set(Calendar.SECOND,0);
+ long time1 = c.getTimeInMillis();
+ c.set(Calendar.HOUR_OF_DAY,00);
+ c.set(Calendar.MINUTE,59);
+ c.set(Calendar.SECOND,59);
+ long time2 = c.getTimeInMillis();
+
+ return new Object[][] {
+ {time1,"0s"},
+ {time1,"0m"},
+ {time1,"23h"},
+ {time2,"59m59s"},
+ {time2,"0h59m59s"}
+ };
+ }
+
+
+
+ /**
+ * Generates data for testing partial date and time assertion syntax.
+ */
+ @DataProvider(name="partialDateTimeSyntaxes")
+ private Object[][] createPartialDateTimeSyntaxes()
+ {
//Get the date today.
+ int second = cal.get(Calendar.SECOND);
+ int minute = cal.get(Calendar.MINUTE);
+ int hour = cal.get(Calendar.HOUR);
int date = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH) + 1;
int year = cal.get(Calendar.YEAR);
@@ -419,24 +466,36 @@
{"20MM30DD1978YY",false},
{"02MM29DD2009YY",false},
{"02MM31DD2010YY",false},
- {"02MM29DD2008YYYY",true},
+ {"-1s",false},
+ {"02M29D2008Y",true},
{"DDYY",false},
- {"02DD",true},
- {"12MM",true},
- {"1978YYYY",true},
+ {"02D",true},
+ {"12M",true},
+ {"1978Y",true},
{"0MM",false},
{"20MM03DD10MM",false},
- {date+"DD",true},
- {month+"MM",true},
- {year+"YYYY",true},
- {month+"MM"+date+"DD",true},
- {year+"YYYY"+date+"DD",true},
- {month+"MM"+year+"YYYY"+date+"DD",true}
+ {"00s12m13h",true},
+ {"00s12m14h1M3D1978Y",true},
+ {"1s",true},
+ {"12m",true},
+ {"23h",true},
+ {"61s",false},
+ {"60m",false},
+ {"24h",false},
+ {second+"s",true},
+ {minute+"m",true},
+ {hour+"h",true},
+ {date+"D",true},
+ {month+"M",true},
+ {year+"Y",true},
+ {month+"M"+date+"D",true},
+ {year+"Y"+date+"D",true},
+ {month+"M"+year+"Y"+date+"D",true}
};
}
-
+
//validate if the args are found in the entries list.
private boolean dnFoundInEntryList( List<SearchResultEntry> entries,DN ... dns)
{
@@ -500,9 +559,9 @@
"dn: cn=user5,dc=example,dc=com",
"objectclass: person",
"objectclass: testoc",
- "cn: user4",
- "sn: user4",
+ "cn: user5",
+ "sn: user5",
"test-time-attribute: " + format(currentTime) // now.
);
}
-}
+ }
--
Gitblit v1.10.0