OPENDJ-1308 Migrate schema support
Added many tests for TimeBasedMatchingRuleFactory in view of porting this class to the SDK.
Started to adapt its API to the SDK APIs.
NotImplementedAssertion.java: ADDED
Added to stop adding the same code for the not implemented Assertion.createIndexQuery().
To be removed once we switch the schema to the SDK.
AbstractMatchingRule.java
Used NotImplementedAssertion.
AbstractOrderingMatchingRule.java:
Implemented getAssertion().
CollationMatchingRuleFactory.java:
Extracted method copyNames().
TimeBasedMatchingRuleFactory.java:
Extracted multiplyByTenThenAddUnits().
Implemented {RelativeTimeGTOrderingMatchingRule|RelativeTimeLTOrderingMatchingRule}.getAssertion() + moved createIndexQuery() to this inner class.
In normalizeAssertionValue(), made code more readable.
Extracted method toCalendarMonth(), isDateInvalid(), isLeapYear(), logAndThrow(), createExactMatchQuery().
Fixed javadocs.
TimeBasedMatchingRuleFactoryTest.java: ADDED
TimeBasedMatchingRuleTest.java:
Code cleanup.
2 files added
5 files modified
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.schema.Syntax; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | |
| | | /** |
| | | * This class provides default implementation of MatchingRule. A |
| | |
| | | throws DecodeException |
| | | { |
| | | final ByteString assertionValue = normalizeAssertionValue(value); |
| | | return new Assertion() |
| | | return new NotImplementedAssertion() |
| | | { |
| | | |
| | | @Override |
| | | public ConditionResult matches(ByteSequence attributeValue) |
| | | { |
| | | return valuesMatch(attributeValue, assertionValue); |
| | | } |
| | | |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) |
| | | throws DecodeException |
| | | { |
| | | throw new RuntimeException("Not implemented"); |
| | | } |
| | | }; |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | | import org.forgerock.opendj.ldap.Assertion; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | |
| | | /** |
| | | * Avoids repeating again and again the same code when |
| | | * Assertion.createIndexQuery() is not implemented. |
| | | * <p> |
| | | * To be removed once we switch the schema to the SDK. |
| | | */ |
| | | public class NotImplementedAssertion implements Assertion |
| | | { |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult matches(ByteSequence normalizedAttributeValue) |
| | | { |
| | | throw new RuntimeException("Not implemented"); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) |
| | | throws DecodeException |
| | | { |
| | | throw new RuntimeException("Not implemented"); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.schema; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.opends.server.api.AbstractMatchingRule; |
| | | import org.opends.server.api.NotImplementedAssertion; |
| | | import org.opends.server.api.OrderingMatchingRule; |
| | | |
| | | /** |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getAssertion(final ByteSequence value) |
| | | throws DecodeException |
| | | { |
| | | final ByteString assertionValue = normalizeAssertionValue(value); |
| | | return new NotImplementedAssertion() |
| | | { |
| | | @Override |
| | | public ConditionResult matches(ByteSequence attributeValue) |
| | | { |
| | | return ConditionResult.valueOf( |
| | | compareValues(assertionValue, attributeValue) < 0); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | |
| | | import org.opends.server.admin.std.meta.CollationMatchingRuleCfgDefn.MatchingRuleType; |
| | | import org.opends.server.admin.std.server.CollationMatchingRuleCfg; |
| | | import org.opends.server.api.*; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.DirectoryException; |
| | |
| | | // If it comes here we don't need to verify MatchingRuleType; it |
| | | // should be okay as its syntax is verified by the admin framework. |
| | | // Iterate over the collations and verify if the format is okay. |
| | | // Also, |
| | | // verify if the locale is allowed by the JVM. |
| | | // Also, verify if the locale is allowed by the JVM. |
| | | for (String collation : configuration.getCollation()) |
| | | { |
| | | CollationMapper mapper = new CollationMapper(collation); |
| | |
| | | |
| | | |
| | | |
| | | private Collection<String> copyNames(MatchingRule matchingRule) |
| | | { |
| | | Collection<String> defaultNames = new HashSet<String>(); |
| | | if (matchingRule != null) |
| | | { |
| | | defaultNames.addAll(matchingRule.getNames()); |
| | | } |
| | | return defaultNames; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates Less-than Matching Rule. |
| | | * |
| | |
| | | String oid = mapper.getNumericOID() + ".1"; |
| | | String lTag = mapper.getLanguageTag(); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | MatchingRule matchingRule = getMatchingRule(oid); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> names = copyNames(getMatchingRule(oid)); |
| | | names.add(lTag + ".lt"); |
| | | names.add(lTag + ".1"); |
| | | |
| | | matchingRule = |
| | | MatchingRule matchingRule = |
| | | new CollationLessThanMatchingRule(oid, names, locale); |
| | | addMatchingRule(oid, matchingRule); |
| | | } |
| | |
| | | String oid = mapper.getNumericOID() + ".2"; |
| | | String lTag = mapper.getLanguageTag(); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | MatchingRule matchingRule = getMatchingRule(oid); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> names = copyNames(getMatchingRule(oid)); |
| | | names.add(lTag + ".lte"); |
| | | names.add(lTag + ".2"); |
| | | |
| | | matchingRule = |
| | | MatchingRule matchingRule = |
| | | new CollationLessThanOrEqualToMatchingRule(oid, names, locale); |
| | | addMatchingRule(oid, matchingRule); |
| | | } |
| | |
| | | String lTag = mapper.getLanguageTag(); |
| | | String nOID = mapper.getNumericOID(); |
| | | |
| | | MatchingRule matchingRule = getMatchingRule(nOID); |
| | | Collection<String> defaultNames = new HashSet<String>(); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | defaultNames.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> defaultNames = copyNames(getMatchingRule(nOID)); |
| | | defaultNames.add(lTag); |
| | | matchingRule = |
| | | new CollationEqualityMatchingRule(nOID, |
| | | defaultNames, locale); |
| | | MatchingRule matchingRule = |
| | | new CollationEqualityMatchingRule(nOID, defaultNames, locale); |
| | | addMatchingRule(nOID, matchingRule); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | // Register OID.3 as the equality matching rule. |
| | | String OID = mapper.getNumericOID() + ".3"; |
| | | MatchingRule equalityMatchingRule = getMatchingRule(OID); |
| | | if (equalityMatchingRule != null) |
| | | { |
| | | for (String name : equalityMatchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> names = copyNames(getMatchingRule(OID)); |
| | | names.add(lTag + ".eq"); |
| | | names.add(lTag + ".3"); |
| | | |
| | | equalityMatchingRule = |
| | | MatchingRule equalityMatchingRule = |
| | | new CollationEqualityMatchingRule(OID, names, locale); |
| | | addMatchingRule(OID, equalityMatchingRule); |
| | | } |
| | |
| | | String oid = mapper.getNumericOID() + ".4"; |
| | | String lTag = mapper.getLanguageTag(); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | MatchingRule matchingRule = getMatchingRule(oid); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> names = copyNames(getMatchingRule(oid)); |
| | | names.add(lTag + ".gte"); |
| | | names.add(lTag + ".4"); |
| | | matchingRule = |
| | | new CollationGreaterThanOrEqualToMatchingRule(oid, names, |
| | | locale); |
| | | |
| | | MatchingRule matchingRule = |
| | | new CollationGreaterThanOrEqualToMatchingRule(oid, names, locale); |
| | | addMatchingRule(oid, matchingRule); |
| | | } |
| | | |
| | |
| | | String oid = mapper.getNumericOID() + ".5"; |
| | | String lTag = mapper.getLanguageTag(); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | MatchingRule matchingRule = getMatchingRule(oid); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | |
| | | Collection<String> names = copyNames(getMatchingRule(oid)); |
| | | names.add(lTag + ".gt"); |
| | | names.add(lTag + ".5"); |
| | | matchingRule = |
| | | |
| | | MatchingRule matchingRule = |
| | | new CollationGreaterThanMatchingRule(oid, names, locale); |
| | | addMatchingRule(oid, matchingRule); |
| | | } |
| | |
| | | String oid = mapper.getNumericOID() + ".6"; |
| | | String lTag = mapper.getLanguageTag(); |
| | | |
| | | Collection<String> names = new HashSet<String>(); |
| | | MatchingRule matchingRule = getMatchingRule(oid); |
| | | if (matchingRule != null) |
| | | { |
| | | for (String name : matchingRule.getNames()) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | Collection<String> names = copyNames(getMatchingRule(oid)); |
| | | names.add(lTag + ".sub"); |
| | | names.add(lTag + ".6"); |
| | | matchingRule = |
| | | |
| | | MatchingRule matchingRule = |
| | | new CollationSubstringMatchingRule(oid, names, locale); |
| | | addMatchingRule(oid, matchingRule); |
| | | } |
| | |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | |
| | | package org.opends.server.schema; |
| | | |
| | | import java.nio.ByteBuffer; |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.Assertion; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.admin.std.server.MatchingRuleCfg; |
| | | import org.opends.server.api.*; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.InitializationException; |
| | |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | import static org.opends.server.util.TimeThread.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class acts as a factory for time-based matching rules. |
| | | */ |
| | |
| | | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | //Greater-than RelativeTimeMatchingRule. |
| | | /** Greater-than RelativeTimeMatchingRule. */ |
| | | private MatchingRule greaterThanRTMRule; |
| | | |
| | | |
| | | //Less-than RelativeTimeMatchingRule. |
| | | /** Less-than RelativeTimeMatchingRule. */ |
| | | private MatchingRule lessThanRTMRule; |
| | | |
| | | |
| | | //PartialDayAndTimeMatchingRule. |
| | | /** PartialDayAndTimeMatchingRule. */ |
| | | private MatchingRule partialDTMatchingRule; |
| | | |
| | | |
| | | //A Collection of matching rules managed by this factory. |
| | | /** A Collection of matching rules managed by this factory. */ |
| | | private Set<MatchingRule> matchingRules; |
| | | |
| | | |
| | | private static final TimeZone TIME_ZONE_UTC_OBJ = |
| | | TimeZone.getTimeZone(TIME_ZONE_UTC); |
| | | |
| | | |
| | | //Constants for generating keys. |
| | | /** Constants for generating keys. */ |
| | | private static final char SECOND = 's'; |
| | | private static final char MINUTE = 'm'; |
| | | private static final char HOUR = 'h'; |
| | |
| | | private static final char YEAR = 'Y'; |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void initializeMatchingRule(MatchingRuleCfg configuration) |
| | | throws ConfigException, InitializationException |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<MatchingRule> getMatchingRules() |
| | | { |
| | |
| | | private abstract class TimeBasedMatchingRule extends AbstractMatchingRule |
| | | implements ExtensibleMatchingRule |
| | | { |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getDescription() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getSyntaxOID() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ByteString normalizeAttributeValue(ByteSequence value) |
| | | throws DecodeException |
| | |
| | | * This value was generated using the <CODE>serialver</CODE> command-line |
| | | * utility included with the Java SDK. |
| | | */ |
| | | private static final long serialVersionUID = -3501812894473163490L; |
| | | private static final long serialVersionUID = -3501812894473163490L; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indexer associated with this instance. |
| | | */ |
| | | protected ExtensibleIndexer indexer; |
| | | /** |
| | | * Indexer associated with this instance. |
| | | */ |
| | | protected ExtensibleIndexer indexer; |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ByteString normalizeAssertionValue(ByteSequence value) |
| | | throws DecodeException |
| | |
| | | long week = 0; |
| | | |
| | | boolean containsTimeUnit = false; |
| | | long number = 0; |
| | | int number = 0; |
| | | |
| | | for(; index<value.length(); index++) |
| | | { |
| | | byte b = value.byteAt(index); |
| | | if(isDigit((char)b)) |
| | | { |
| | | switch (value.byteAt(index)) |
| | | { |
| | | case '0': |
| | | number = (number * 10); |
| | | break; |
| | | |
| | | case '1': |
| | | number = (number * 10) + 1; |
| | | break; |
| | | |
| | | case '2': |
| | | number = (number * 10) + 2; |
| | | break; |
| | | |
| | | case '3': |
| | | number = (number * 10) + 3; |
| | | break; |
| | | |
| | | case '4': |
| | | number = (number * 10) + 4; |
| | | break; |
| | | |
| | | case '5': |
| | | number = (number * 10) + 5; |
| | | break; |
| | | |
| | | case '6': |
| | | number = (number * 10) + 6; |
| | | break; |
| | | |
| | | case '7': |
| | | number = (number * 10) + 7; |
| | | break; |
| | | |
| | | case '8': |
| | | number = (number * 10) + 8; |
| | | break; |
| | | |
| | | case '9': |
| | | number = (number * 10) + 9; |
| | | break; |
| | | } |
| | | number = multiplyByTenThenAddUnits(number, b); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | switch(value.byteAt(index)) |
| | | switch(b) |
| | | { |
| | | case 's': |
| | | second = number; |
| | |
| | | week = number; |
| | | break; |
| | | default: |
| | | message = WARN_ATTR_INVALID_RELATIVE_TIME_ASSERTION_FORMAT. |
| | | get(value,(char)value.byteAt(index)); |
| | | message = WARN_ATTR_INVALID_RELATIVE_TIME_ASSERTION_FORMAT.get(value, (char) b); |
| | | } |
| | | } |
| | | if(message !=null) |
| | |
| | | logger.error(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | else |
| | | { |
| | | containsTimeUnit = true; |
| | | number = 0; |
| | | } |
| | | containsTimeUnit = true; |
| | | number = 0; |
| | | } |
| | | } |
| | | |
| | |
| | | long delta = (second + minute*60 + hour*3600 + day*24*3600 + |
| | | week*7*24*3600)*1000 ; |
| | | long now = getTime(); |
| | | return signed?ByteString.valueOf(now-delta): |
| | | ByteString.valueOf(now+delta); |
| | | return ByteString.valueOf(signed ? now - delta : now + delta); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int compareValues(ByteSequence value1, ByteSequence value2) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int compare(byte[] arg0, byte[] arg1) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<ExtensibleIndexer> getIndexers( |
| | | IndexingOptions indexingOptions) |
| | |
| | | { |
| | | indexer = new RelativeTimeExtensibleIndexer(this); |
| | | } |
| | | return Collections.singletonList(indexer); |
| | | return Collections.singletonList(indexer); |
| | | } |
| | | } |
| | | |
| | |
| | | private final class RelativeTimeGTOrderingMatchingRule |
| | | extends RelativeTimeOrderingMatchingRule |
| | | { |
| | | //All the names for this matching rule. |
| | | /** All the names for this matching rule. */ |
| | | private final List<String> names; |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<String> getNames() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getOID() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult valuesMatch(ByteSequence attributeValue, |
| | | ByteSequence assertionValue) |
| | |
| | | return ConditionResult.valueOf(ret > 0); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getAssertion(final ByteSequence value) |
| | | throws DecodeException |
| | | { |
| | | final ByteString assertionValue = normalizeAssertionValue(value); |
| | | return new Assertion() |
| | | { |
| | | @Override |
| | | public ConditionResult matches(ByteSequence attributeValue) |
| | | { |
| | | return valuesMatch(attributeValue, assertionValue); |
| | | } |
| | | |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) |
| | | throws DecodeException |
| | | { |
| | | return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(), |
| | | assertionValue, ByteString.empty(), false, false); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public <T> T createIndexQuery(ByteSequence assertionValue, |
| | | IndexQueryFactory<T> factory) throws DecodeException |
| | | { |
| | | return factory.createRangeMatchQuery(indexer |
| | | .getExtensibleIndexID(), normalizeAssertionValue(assertionValue), |
| | | ByteString.empty(), false, false); |
| | | return getAssertion(assertionValue).createIndexQuery(factory); |
| | | } |
| | | } |
| | | |
| | |
| | | private final class RelativeTimeLTOrderingMatchingRule |
| | | extends RelativeTimeOrderingMatchingRule |
| | | { |
| | | //All the names for this matching rule. |
| | | /** All the names for this matching rule. */ |
| | | private final List<String> names; |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<String> getNames() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getOID() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult valuesMatch(ByteSequence attributeValue, |
| | | ByteSequence assertionValue) |
| | |
| | | return ConditionResult.valueOf(ret < 0); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Assertion getAssertion(final ByteSequence value) |
| | | throws DecodeException |
| | | { |
| | | final ByteString assertionValue = normalizeAssertionValue(value); |
| | | return new Assertion() |
| | | { |
| | | @Override |
| | | public ConditionResult matches(ByteSequence attributeValue) |
| | | { |
| | | return valuesMatch(attributeValue, assertionValue); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <T> T createIndexQuery(IndexQueryFactory<T> factory) |
| | | throws DecodeException |
| | | { |
| | | return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(), |
| | | ByteString.empty(), assertionValue, false, false); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public <T> T createIndexQuery(ByteSequence assertionValue, |
| | | IndexQueryFactory<T> factory) throws DecodeException |
| | | { |
| | | return factory.createRangeMatchQuery(indexer |
| | | .getExtensibleIndexID(), ByteString.empty(), |
| | | normalizeAssertionValue(assertionValue),false, false); |
| | | return getAssertion(assertionValue).createIndexQuery(factory); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getExtensibleIndexID() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final void createKeys(Schema schema, ByteSequence value2, |
| | | IndexingOptions options, Collection<ByteString> keys) |
| | |
| | | private final class PartialDateAndTimeMatchingRule |
| | | extends TimeBasedMatchingRule |
| | | { |
| | | /** |
| | | * Indexer associated with this instance. |
| | | */ |
| | | private ExtensibleIndexer indexer; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Indexer associated with this instance. |
| | | */ |
| | | private ExtensibleIndexer indexer; |
| | | |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getOID() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<String> getNames() |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ByteString normalizeAssertionValue(ByteSequence value) |
| | | throws DecodeException |
| | |
| | | into a format to be recognized by the compare routine. The normalized |
| | | value is actually the format of : smhDMY. |
| | | */ |
| | | int second = -1; |
| | | int minute = -1; |
| | | int hour = -1; |
| | | int date = 0; |
| | | int year = 0; |
| | | final int initDate = 0; |
| | | final int initVal = -1; |
| | | int second = initVal; |
| | | int minute = initVal; |
| | | int hour = initVal; |
| | | int date = initDate; |
| | | int month = initVal; |
| | | int year = initDate; |
| | | int number = 0; |
| | | int month = -1; |
| | | |
| | | int length = value.length(); |
| | | for(int index=0; index<length; index++) |
| | |
| | | byte b = value.byteAt(index); |
| | | if(isDigit((char)b)) |
| | | { |
| | | switch (value.byteAt(index)) |
| | | { |
| | | case '0': |
| | | number = (number * 10); |
| | | break; |
| | | |
| | | case '1': |
| | | number = (number * 10) + 1; |
| | | break; |
| | | |
| | | case '2': |
| | | number = (number * 10) + 2; |
| | | break; |
| | | |
| | | case '3': |
| | | number = (number * 10) + 3; |
| | | break; |
| | | |
| | | case '4': |
| | | number = (number * 10) + 4; |
| | | break; |
| | | |
| | | case '5': |
| | | number = (number * 10) + 5; |
| | | break; |
| | | |
| | | case '6': |
| | | number = (number * 10) + 6; |
| | | break; |
| | | |
| | | case '7': |
| | | number = (number * 10) + 7; |
| | | break; |
| | | |
| | | case '8': |
| | | number = (number * 10) + 8; |
| | | break; |
| | | |
| | | case '9': |
| | | number = (number * 10) + 9; |
| | | break; |
| | | } |
| | | number = multiplyByTenThenAddUnits(number, b); |
| | | } |
| | | else |
| | | { |
| | | LocalizableMessage message = null; |
| | | switch(value.byteAt(index)) |
| | | switch(b) |
| | | { |
| | | case 's': |
| | | if(second >0) |
| | | if (second != initVal) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_SECOND_ASSERTION_FORMAT.get(value, date); |
| | | } |
| | |
| | | } |
| | | break; |
| | | case 'm': |
| | | if(minute >0) |
| | | if (minute != initVal) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_MINUTE_ASSERTION_FORMAT.get(value, date); |
| | | } |
| | |
| | | } |
| | | break; |
| | | case 'h': |
| | | if(hour >0) |
| | | if (hour != initVal) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_HOUR_ASSERTION_FORMAT.get(value, date); |
| | | } |
| | |
| | | { |
| | | message = WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT.get(value, number); |
| | | } |
| | | else if(date > 0) |
| | | else if (date != initDate) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_DATE_ASSERTION_FORMAT.get(value, date); |
| | | } |
| | |
| | | } |
| | | break; |
| | | case 'M': |
| | | if(number == 0) |
| | | if (number == 0) |
| | | { |
| | | message = WARN_ATTR_INVALID_MONTH_ASSERTION_FORMAT.get(value, number); |
| | | } |
| | | else if(month > 0) |
| | | else if (month != initVal) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_MONTH_ASSERTION_FORMAT.get(value, month); |
| | | } |
| | |
| | | { |
| | | message = WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT.get(value, number); |
| | | } |
| | | else if(year >0) |
| | | else if (year != initDate) |
| | | { |
| | | message = WARN_ATTR_DUPLICATE_YEAR_ASSERTION_FORMAT.get(value, year); |
| | | } |
| | |
| | | } |
| | | break; |
| | | default: |
| | | message = WARN_ATTR_INVALID_PARTIAL_TIME_ASSERTION_FORMAT. |
| | | get(value,(char)value.byteAt(index)); |
| | | message = WARN_ATTR_INVALID_PARTIAL_TIME_ASSERTION_FORMAT.get(value, (char) b); |
| | | } |
| | | if(message !=null) |
| | | { |
| | | logger.error(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | else |
| | | { |
| | | number = 0; |
| | | } |
| | | number = 0; |
| | | } |
| | | } |
| | | |
| | | month = toCalendarMonth(month, value); |
| | | |
| | | //Validate year, month , date , hour, minute and second in that order. |
| | | if(year < 0) |
| | | // -1 values are allowed when these values have not been provided |
| | | if (year < 0) |
| | | { |
| | | //A future date is allowed. |
| | | LocalizableMessage message = WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT.get(value, year); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | logAndThrow(WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT.get(value, year)); |
| | | } |
| | | if (isDateInvalid(date, month, year)) |
| | | { |
| | | logAndThrow(WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT.get(value, date)); |
| | | } |
| | | if (hour < initVal || hour > 23) |
| | | { |
| | | logAndThrow(WARN_ATTR_INVALID_HOUR_ASSERTION_FORMAT.get(value, hour)); |
| | | } |
| | | if (minute < initVal || minute > 59) |
| | | { |
| | | logAndThrow(WARN_ATTR_INVALID_MINUTE_ASSERTION_FORMAT.get(value, minute)); |
| | | } |
| | | if (second < initVal || second > 60) // Consider leap seconds. |
| | | { |
| | | logAndThrow(WARN_ATTR_INVALID_SECOND_ASSERTION_FORMAT.get(value, second)); |
| | | } |
| | | |
| | | switch(month) |
| | | { |
| | | case -1: |
| | | //just allow this. |
| | | break; |
| | | case 1: |
| | | month = Calendar.JANUARY; |
| | | break; |
| | | case 2: |
| | | month = Calendar.FEBRUARY; |
| | | break; |
| | | case 3: |
| | | month = Calendar.MARCH; |
| | | break; |
| | | case 4: |
| | | month = Calendar.APRIL; |
| | | break; |
| | | case 5: |
| | | month = Calendar.MAY; |
| | | break; |
| | | case 6: |
| | | month = Calendar.JUNE; |
| | | break; |
| | | case 7: |
| | | month = Calendar.JULY; |
| | | break; |
| | | case 8: |
| | | month = Calendar.AUGUST; |
| | | break; |
| | | case 9: |
| | | month = Calendar.SEPTEMBER; |
| | | break; |
| | | case 10: |
| | | month = Calendar.OCTOBER; |
| | | break; |
| | | case 11: |
| | | month = Calendar.NOVEMBER; |
| | | break; |
| | | case 12: |
| | | month = Calendar.DECEMBER; |
| | | break; |
| | | default: |
| | | LocalizableMessage message = WARN_ATTR_INVALID_MONTH_ASSERTION_FORMAT.get(value, month); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | boolean invalidDate = false; |
| | | switch(date) |
| | | { |
| | | case 29: |
| | | if(month == Calendar.FEBRUARY && year%4 !=0) |
| | | { |
| | | invalidDate = true; |
| | | } |
| | | break; |
| | | case 31: |
| | | if(month != -1 && month != Calendar.JANUARY && month!= Calendar.MARCH |
| | | && month != Calendar.MAY && month != Calendar.JULY |
| | | && month != Calendar.AUGUST && month != Calendar.OCTOBER |
| | | && month != Calendar.DECEMBER) |
| | | { |
| | | invalidDate = true; |
| | | } |
| | | break; |
| | | default: |
| | | if(!(date >=0 && date <=31)) |
| | | { |
| | | invalidDate = true; |
| | | } |
| | | } |
| | | if(invalidDate) |
| | | { |
| | | LocalizableMessage message = WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT.get(value, date); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | if(!(hour >=-1 && hour <=23)) |
| | | { |
| | | LocalizableMessage message = WARN_ATTR_INVALID_HOUR_ASSERTION_FORMAT.get(value, date); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | if(!(minute >=-1 && minute <=59)) |
| | | { |
| | | LocalizableMessage message = WARN_ATTR_INVALID_MINUTE_ASSERTION_FORMAT.get(value, date); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | if(!(second >=-1 && second <=60)) //Consider leap seconds. |
| | | { |
| | | LocalizableMessage message = WARN_ATTR_INVALID_SECOND_ASSERTION_FORMAT.get(value, date); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | /** |
| | | * Since we reached here we have a valid assertion value. Construct |
| | | * a normalized value in the order: SECOND MINUTE HOUR DATE MONTH YEAR. |
| | | */ |
| | | // Since we reached here we have a valid assertion value. |
| | | // Construct a normalized value in the order: SECOND MINUTE HOUR DATE MONTH YEAR. |
| | | ByteBuffer bb = ByteBuffer.allocate(6*4); |
| | | bb.putInt(second); |
| | | bb.putInt(minute); |
| | |
| | | return ByteString.wrap(bb.array()); |
| | | } |
| | | |
| | | private void logAndThrow(LocalizableMessage message) throws DecodeException |
| | | { |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | private boolean isDateInvalid(int date, int month, int year) |
| | | { |
| | | switch (date) |
| | | { |
| | | case 29: |
| | | return month == Calendar.FEBRUARY && !isLeapYear(year); |
| | | case 30: |
| | | return month == Calendar.FEBRUARY; |
| | | case 31: |
| | | return month != -1 && month != Calendar.JANUARY |
| | | && month != Calendar.MARCH && month != Calendar.MAY |
| | | && month != Calendar.JULY && month != Calendar.AUGUST |
| | | && month != Calendar.OCTOBER && month != Calendar.DECEMBER; |
| | | default: |
| | | return date < 0 || date > 31; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | private boolean isLeapYear(int year) |
| | | { |
| | | if (year % 400 == 0) |
| | | { |
| | | return true; |
| | | } |
| | | if (year % 100 == 0) |
| | | { |
| | | return false; |
| | | } |
| | | return year % 4 == 0; |
| | | } |
| | | |
| | | private int toCalendarMonth(int month, ByteSequence value) throws DecodeException |
| | | { |
| | | switch (month) |
| | | { |
| | | case -1: |
| | | // just allow this. |
| | | return -1; |
| | | case 1: |
| | | return Calendar.JANUARY; |
| | | case 2: |
| | | return Calendar.FEBRUARY; |
| | | case 3: |
| | | return Calendar.MARCH; |
| | | case 4: |
| | | return Calendar.APRIL; |
| | | case 5: |
| | | return Calendar.MAY; |
| | | case 6: |
| | | return Calendar.JUNE; |
| | | case 7: |
| | | return Calendar.JULY; |
| | | case 8: |
| | | return Calendar.AUGUST; |
| | | case 9: |
| | | return Calendar.SEPTEMBER; |
| | | case 10: |
| | | return Calendar.OCTOBER; |
| | | case 11: |
| | | return Calendar.NOVEMBER; |
| | | case 12: |
| | | return Calendar.DECEMBER; |
| | | default: |
| | | LocalizableMessage message = WARN_ATTR_INVALID_MONTH_ASSERTION_FORMAT.get(value, month); |
| | | logger.warn(message); |
| | | throw DecodeException.error(message); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult valuesMatch(ByteSequence attributeValue, |
| | | ByteSequence assertionValue) |
| | | { |
| | | long timeInMS = ((ByteString)attributeValue).toLong(); |
| | | //Build the information from the attribute value. |
| | | // Build the information from the attribute value. |
| | | GregorianCalendar cal = new GregorianCalendar(TIME_ZONE_UTC_OBJ); |
| | | cal.setLenient(false); |
| | | cal.setTimeInMillis(timeInMS); |
| | | cal.setTimeInMillis(((ByteString) attributeValue).toLong()); |
| | | int second = cal.get(Calendar.SECOND); |
| | | int minute = cal.get(Calendar.MINUTE); |
| | | int hour = cal.get(Calendar.HOUR_OF_DAY); |
| | |
| | | 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 assertSecond = bb.getInt(0); |
| | |
| | | int assertMonth = bb.getInt(16); |
| | | int assertYear = bb.getInt(20); |
| | | |
| | | // All the non-zero and non -1 values should match. |
| | | if ((assertSecond != -1 && assertSecond != second) |
| | | || (assertMinute != -1 && assertMinute != minute) |
| | | || (assertHour != -1 && assertHour != hour) |
| | | // All the non-zero values should match. |
| | | || (assertDate != 0 && assertDate != date) |
| | | || (assertMonth != -1 && assertMonth != month) |
| | | || (assertYear != 0 && assertYear != year)) |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Collection<ExtensibleIndexer> getIndexers( |
| | | IndexingOptions indexingOptions) |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public <T> T createIndexQuery(ByteSequence assertionValue, |
| | | IndexQueryFactory<T> factory) throws DecodeException |
| | |
| | | int assertDate = bb.getInt(12); |
| | | int assertMonth = bb.getInt(16); |
| | | int assertYear = bb.getInt(20); |
| | | List<T> queries = new ArrayList<T>(); |
| | | |
| | | List<T> queries = new ArrayList<T>(); |
| | | if(assertSecond >= 0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertSecond,SECOND))); |
| | | queries.add(createExactMatchQuery(factory, assertSecond, SECOND)); |
| | | } |
| | | |
| | | if(assertMinute >=0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertMinute,MINUTE))); |
| | | queries.add(createExactMatchQuery(factory, assertMinute, MINUTE)); |
| | | } |
| | | |
| | | if(assertHour >=0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertHour,HOUR))); |
| | | queries.add(createExactMatchQuery(factory, assertHour, HOUR)); |
| | | } |
| | | |
| | | if(assertDate >0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertDate,DATE))); |
| | | queries.add(createExactMatchQuery(factory, assertDate, DATE)); |
| | | } |
| | | |
| | | if(assertMonth >=0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertMonth,MONTH))); |
| | | queries.add(createExactMatchQuery(factory, assertMonth, MONTH)); |
| | | } |
| | | |
| | | if(assertYear > 0) |
| | | { |
| | | queries.add(factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), |
| | | getKey(assertYear,YEAR))); |
| | | queries.add(createExactMatchQuery(factory, assertYear, YEAR)); |
| | | } |
| | | return factory.createIntersectionQuery(queries); |
| | | } |
| | | |
| | | private <T> T createExactMatchQuery(IndexQueryFactory<T> factory, |
| | | int assertionValue, char type) |
| | | { |
| | | return factory.createExactMatchQuery( |
| | | indexer.getExtensibleIndexID(), getKey(assertionValue, type)); |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | |
| | | private int multiplyByTenThenAddUnits(int number, byte b) |
| | | { |
| | | switch (b) |
| | | { |
| | | case '0': |
| | | return number * 10; |
| | | case '1': |
| | | return number * 10 + 1; |
| | | case '2': |
| | | return number * 10 + 2; |
| | | case '3': |
| | | return number * 10 + 3; |
| | | case '4': |
| | | return number * 10 + 4; |
| | | case '5': |
| | | return number * 10 + 5; |
| | | case '6': |
| | | return number * 10 + 6; |
| | | case '7': |
| | | return number * 10 + 7; |
| | | case '8': |
| | | return number * 10 + 8; |
| | | case '9': |
| | | return number * 10 + 9; |
| | | } |
| | | return number; |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | private final class PartialDateAndTimeExtensibleIndexer extends |
| | | ExtensibleIndexer |
| | | { |
| | | // The partial date and Time matching Rule. |
| | | /** The partial date and Time matching Rule. */ |
| | | private final PartialDateAndTimeMatchingRule matchingRule; |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, |
| | | IndexingOptions options, Collection<ByteString> keys) |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getExtensibleIndexID() |
| | | { |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.schema; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.*; |
| | | |
| | | import org.forgerock.opendj.ldap.Assertion; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.admin.std.server.CollationMatchingRuleCfg; |
| | | import org.opends.server.admin.std.server.MatchingRuleCfg; |
| | | import org.opends.server.api.MatchingRule; |
| | | import org.opends.server.util.TimeThread; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.assertj.core.api.Assertions.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | public class TimeBasedMatchingRuleFactoryTest extends SchemaTestCase |
| | | { |
| | | |
| | | private static final String LESS_THAN_RELATIVE_TIME = "relativeTimeLTOrderingMatch"; |
| | | private static final String GREATER_THAN_RELATIVE_TIME = "relativeTimeGTOrderingMatch"; |
| | | private static final String PARTIAL_DATE_AND_TIME = "partialDateAndTimeMatchingRule"; |
| | | |
| | | @DataProvider |
| | | public Iterator<Object[]> validAssertionValuesDataProvider() |
| | | { |
| | | final SimpleDateFormat generalizedTimeFormatter = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); |
| | | final Calendar cal = TimeThread.getCalendar(); |
| | | final Date nowDate = cal.getTime(); |
| | | final String nowGT = generalizedTimeFormatter.format(nowDate); |
| | | cal.add(Calendar.MONTH, 1); |
| | | final Date oneMonthAheadDate = cal.getTime(); |
| | | final String oneMonthAheadGT = generalizedTimeFormatter.format(oneMonthAheadDate); |
| | | |
| | | final Collection<Object[]> results = new LinkedList<Object[]>(Arrays.asList(new Object[][] { |
| | | { LESS_THAN_RELATIVE_TIME, /* now + */"1"/* s */, oneMonthAheadGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now + */"1"/* s */, oneMonthAheadGT, ConditionResult.TRUE }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"+1s", oneMonthAheadGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now */"+1s", oneMonthAheadGT, ConditionResult.TRUE }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"+1m", oneMonthAheadGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now */"+1m", oneMonthAheadGT, ConditionResult.TRUE }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"+1h", oneMonthAheadGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now */"+1h", oneMonthAheadGT, ConditionResult.TRUE }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"-30d", nowGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now */"-30d", nowGT, ConditionResult.TRUE }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"-30w", nowGT, ConditionResult.FALSE }, |
| | | { GREATER_THAN_RELATIVE_TIME, /* now */"-30w", nowGT, ConditionResult.TRUE }, |
| | | // 29th of months and leap years |
| | | { PARTIAL_DATE_AND_TIME, "2012Y03M29D", "20120329120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y02M29D", "20120229120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2000Y02M29D", "20000229120000Z", ConditionResult.TRUE }, |
| | | // Generalized time implementation does not allow leap seconds |
| | | // because Java does not support them. Apparently, it never will support them: |
| | | // @see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4272347 |
| | | // leap seconds are allowed, even though no formula exists to validate them |
| | | { PARTIAL_DATE_AND_TIME, "2012Y06M30D23h59m60s", "20120630235959Z", ConditionResult.FALSE }, |
| | | // no match |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20111231235930Z", ConditionResult.FALSE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20121031235930Z", ConditionResult.FALSE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20121230235930Z", ConditionResult.FALSE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20121231225930Z", ConditionResult.FALSE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20121231235830Z", ConditionResult.FALSE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D23h59m30s", "20121231235829Z", ConditionResult.FALSE }, |
| | | // 30th of months |
| | | { PARTIAL_DATE_AND_TIME, "1982Y09M30D", "19820930120000Z", ConditionResult.TRUE }, |
| | | // 31st of months |
| | | { PARTIAL_DATE_AND_TIME, "2012Y01M31D", "20120131120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y03M31D", "20120331120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y05M31D", "20120531120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y07M31D", "20120731120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y08M31D", "20120831120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y10M31D", "20121031120000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M31D", "20121231120000Z", ConditionResult.TRUE }, |
| | | // Only single time units |
| | | { PARTIAL_DATE_AND_TIME, "2012Y", "20121231123000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12M", "20121231123000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y31D", "20121231123000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y12h", "20121231123000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y30m", "20121231123000Z", ConditionResult.TRUE }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y0s", "20121231123000Z", ConditionResult.TRUE }, |
| | | })); |
| | | addPartialDateAndTimeData(results, nowDate, oneMonthAheadDate); |
| | | return results.iterator(); |
| | | } |
| | | |
| | | private void addPartialDateAndTimeData(Collection<Object[]> results, Date... dates) |
| | | { |
| | | final SimpleDateFormat ptFormatterUpToSeconds = new SimpleDateFormat("yyyy'Y'MM'M'dd'D'HH'h'mm'm'ss's'"); |
| | | final SimpleDateFormat ptFormatterUpToMinutes = new SimpleDateFormat("yyyy'Y'MM'M'dd'D'HH'h'mm'm'"); |
| | | final SimpleDateFormat ptFormatterUpToHours = new SimpleDateFormat("yyyy'Y'MM'M'dd'D'HH'h'"); |
| | | final SimpleDateFormat gtFormatterUpToSeconds = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); |
| | | final SimpleDateFormat gtFormatterUpToMinutes = new SimpleDateFormat("yyyyMMddHHmm'Z'"); |
| | | final SimpleDateFormat gtFormatterUpToHours = new SimpleDateFormat("yyyyMMddHH'Z'"); |
| | | |
| | | for (Date date : dates) |
| | | { |
| | | String ptUpToSeconds = ptFormatterUpToSeconds.format(date); |
| | | String gtUpToSeconds = gtFormatterUpToSeconds.format(date); |
| | | results.add(new Object[] { PARTIAL_DATE_AND_TIME, ptUpToSeconds, gtUpToSeconds, ConditionResult.TRUE }); |
| | | String ptUpToMinutes = ptFormatterUpToMinutes.format(date); |
| | | String gtUpToMinutes = gtFormatterUpToMinutes.format(date); |
| | | results.add(new Object[] { PARTIAL_DATE_AND_TIME, ptUpToMinutes, gtUpToMinutes, ConditionResult.TRUE }); |
| | | String ptUpToHours = ptFormatterUpToHours.format(date); |
| | | String gtUpToHours = gtFormatterUpToHours.format(date); |
| | | results.add(new Object[] { PARTIAL_DATE_AND_TIME, ptUpToHours, gtUpToHours, ConditionResult.TRUE }); |
| | | } |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] invalidAssertionValuesDataProvider() |
| | | { |
| | | final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHH"); |
| | | final Calendar cal = TimeThread.getCalendar(); |
| | | final String now = dateFormatter.format(cal.getTime()) + "Z"; |
| | | |
| | | return new Object[][] { |
| | | // { LESS_THAN_RELATIVE_TIME, "", now, null }, |
| | | { LESS_THAN_RELATIVE_TIME, "bla", now, null }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"-30b", now, null }, |
| | | { LESS_THAN_RELATIVE_TIME, /* now */"-30ms", now, null }, |
| | | |
| | | // { PARTIAL_DATE_AND_TIME, "", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "bla", now, null }, |
| | | // invalid time unit values |
| | | { PARTIAL_DATE_AND_TIME, "-1Y03M11D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "0Y03M11D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y-1M11D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y0M11D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y13M11D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M-1D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M0D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y13M32D12h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D-1h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D24h48m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h-1m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h60m32s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h48m-1s", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h48m61s", now, null }, |
| | | // duplicate each time unit |
| | | { PARTIAL_DATE_AND_TIME, "1Y2014Y03M11D12h", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y1M03M11D12h", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M1D11D12h", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D1h12h", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h1m48m", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2014Y03M11D12h48m1s32s", now, null }, |
| | | // February and non leap years |
| | | { PARTIAL_DATE_AND_TIME, "2014Y02M29D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "1800Y02M29D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2000Y02M30D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2000Y02M31D", now, null }, |
| | | // 31st of months |
| | | { PARTIAL_DATE_AND_TIME, "2012Y04M31D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y06M31D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y09M31D", now, null }, |
| | | { PARTIAL_DATE_AND_TIME, "2012Y11M31D", now, null }, |
| | | }; |
| | | } |
| | | |
| | | @Test(dataProvider = "validAssertionValuesDataProvider") |
| | | public void testValidAssertionValues(String matchingRuleName, |
| | | String assertionValue, String attributeValue, |
| | | ConditionResult expectedResult) throws Exception |
| | | { |
| | | final MatchingRule rule = getMatchingRule(matchingRuleName); |
| | | |
| | | Assertion assertion = rule.getAssertion(ByteString.valueOf(assertionValue)); |
| | | ByteString normalizedAttributeValue = |
| | | rule.normalizeAttributeValue(ByteString.valueOf(attributeValue)); |
| | | assertThat(assertion.matches(normalizedAttributeValue)).isEqualTo(expectedResult); |
| | | } |
| | | |
| | | @Test(dataProvider = "invalidAssertionValuesDataProvider", |
| | | expectedExceptions = DecodeException.class) |
| | | public void testInvalidAssertionValues(String matchingRuleName, |
| | | String assertionValue, String attributeValue, |
| | | ConditionResult expectedResult) throws Exception |
| | | { |
| | | testValidAssertionValues(matchingRuleName, assertionValue, attributeValue, expectedResult); |
| | | } |
| | | |
| | | private MatchingRule getMatchingRule(String matchingRuleName) throws Exception |
| | | { |
| | | final Collection<MatchingRule> mRules = getMatchingRules(); |
| | | assertThat(mRules).hasSize(3); |
| | | for (MatchingRule mRule : mRules) |
| | | { |
| | | if (mRule.getNameOrOID().equals(matchingRuleName)) |
| | | { |
| | | return mRule; |
| | | } |
| | | } |
| | | fail("Could not find a matching rule named '" + matchingRuleName + "'"); |
| | | return null; |
| | | } |
| | | |
| | | private Collection<MatchingRule> getMatchingRules() throws Exception |
| | | { |
| | | final TimeBasedMatchingRuleFactory factory = |
| | | new TimeBasedMatchingRuleFactory(); |
| | | final MatchingRuleCfg cfg = mock(CollationMatchingRuleCfg.class); |
| | | factory.initializeMatchingRule(cfg); |
| | | final Collection<MatchingRule> mRules = factory.getMatchingRules(); |
| | | verifyNoMoreInteractions(cfg); |
| | | return mRules; |
| | | } |
| | | } |
| | |
| | | import java.util.List; |
| | | import java.util.TimeZone; |
| | | |
| | | import org.assertj.core.api.Assertions; |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.api.MatchingRule; |
| | |
| | | "objectclasses: ( testoc-oid NAME 'testOC' SUP top AUXILIARY MUST test-time)", |
| | | "objectclasses: ( testoc2-oid NAME 'testOC2' SUP top AUXILIARY MUST test-date)" |
| | | ); |
| | | assertTrue(resultCode == 0); |
| | | assertEquals(0, resultCode); |
| | | } |
| | | |
| | | |
| | |
| | | searchOperation.run(); |
| | | assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); |
| | | List<SearchResultEntry> entries = searchOperation.getSearchEntries(); |
| | | assertTrue(entries.size()==3 && dnFoundInEntryList(entries,user3,user4,user5)); |
| | | Assertions.assertThat(entries).hasSize(3); |
| | | assertTrue(dnFoundInEntryList(entries, user3, user4, user5)); |
| | | } |
| | | finally |
| | | { |
| | |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | //validate if the args are found in the entries list. |
| | | private boolean dnFoundInEntryList( List<SearchResultEntry> entries,DN ... dns) |
| | | // validate if the args are found in the entries list. |
| | | private boolean dnFoundInEntryList(List<SearchResultEntry> entries, DN... dns) |
| | | { |
| | | for(DN dn: dns) |
| | | for (DN dn : dns) |
| | | { |
| | | boolean found = false; |
| | | for(SearchResultEntry entry: entries) |
| | | { |
| | | System.out.println("dn from the current entry is " + entry.getName()); |
| | | if(entry.getName().equals(dn)) |
| | | { |
| | | found = true; |
| | | } |
| | | } |
| | | if(!found) |
| | | { |
| | | return false; |
| | | } |
| | | assertTrue(find(entries, dn), "Could not find dn " + dn + " in list " + entries); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private boolean find(List<SearchResultEntry> entries, DN dn) |
| | | { |
| | | for (SearchResultEntry entry : entries) |
| | | { |
| | | if (entry.getName().equals(dn)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | //Creates the entries. |
| | | private void populateEntries() throws Exception |