001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.matchingrules;
022
023
024
025import java.io.Serializable;
026
027import com.unboundid.asn1.ASN1OctetString;
028import com.unboundid.ldap.sdk.LDAPException;
029import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition;
030import com.unboundid.ldap.sdk.schema.Schema;
031import com.unboundid.util.Extensible;
032import com.unboundid.util.ThreadSafety;
033import com.unboundid.util.ThreadSafetyLevel;
034
035import static com.unboundid.util.StaticUtils.*;
036
037
038
039/**
040 * This class defines the API for an LDAP matching rule, which may be used to
041 * determine whether two values are equal to each other, and to normalize values
042 * so that they may be more easily compared.
043 */
044@Extensible()
045@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
046public abstract class MatchingRule
047       implements Serializable
048{
049  /**
050   * The substring element type used for subInitial substring assertion
051   * components.
052   */
053  public static final byte SUBSTRING_TYPE_SUBINITIAL = (byte) 0x80;
054
055
056
057  /**
058   * The substring element type used for subAny substring assertion components.
059   */
060  public static final byte SUBSTRING_TYPE_SUBANY = (byte) 0x81;
061
062
063
064  /**
065   * The substring element type used for subFinal substring assertion
066   * components.
067   */
068  public static final byte SUBSTRING_TYPE_SUBFINAL = (byte) 0x82;
069
070
071
072  /**
073   * The serial version UID for this serializable class.
074   */
075  private static final long serialVersionUID = 6050276733546358513L;
076
077
078
079  /**
080   * Creates a new instance of this matching rule.
081   */
082  protected MatchingRule()
083  {
084    // No implementation is required.
085  }
086
087
088
089  /**
090   * Retrieves the name for this matching rule when used to perform equality
091   * matching, if appropriate.
092   *
093   * @return  The name for this matching rule when used to perform equality
094   *          matching, or {@code null} if this matching rule is not intended
095   *          to be used for equality matching.
096   */
097  public abstract String getEqualityMatchingRuleName();
098
099
100
101  /**
102   * Retrieves the OID for this matching rule when used to perform equality
103   * matching, if appropriate.
104   *
105   * @return  The OID for this matching rule when used to perform equality
106   *          matching, or {@code null} if this matching rule is not intended
107   *          to be used for equality matching.
108   */
109  public abstract String getEqualityMatchingRuleOID();
110
111
112
113  /**
114   * Retrieves the name for this matching rule when used to perform equality
115   * matching if defined, or the OID if no name is available.
116   *
117   * @return  The name or OID for this matching rule when used to perform
118   *          equality matching, or {@code null} if this matching rule cannot
119   *          be used to perform equality matching.
120   */
121  public String getEqualityMatchingRuleNameOrOID()
122  {
123    final String name = getEqualityMatchingRuleName();
124    if (name == null)
125    {
126      return getEqualityMatchingRuleOID();
127    }
128    else
129    {
130      return name;
131    }
132  }
133
134
135
136  /**
137   * Retrieves the name for this matching rule when used to perform ordering
138   * matching, if appropriate.
139   *
140   * @return  The name for this matching rule when used to perform ordering
141   *          matching, or {@code null} if this matching rule is not intended
142   *          to be used for ordering matching.
143   */
144  public abstract String getOrderingMatchingRuleName();
145
146
147
148  /**
149   * Retrieves the OID for this matching rule when used to perform ordering
150   * matching, if appropriate.
151   *
152   * @return  The OID for this matching rule when used to perform ordering
153   *          matching, or {@code null} if this matching rule is not intended
154   *          to be used for ordering matching.
155   */
156  public abstract String getOrderingMatchingRuleOID();
157
158
159
160  /**
161   * Retrieves the name for this matching rule when used to perform ordering
162   * matching if defined, or the OID if no name is available.
163   *
164   * @return  The name or OID for this matching rule when used to perform
165   *          ordering matching, or {@code null} if this matching rule cannot
166   *          be used to perform equality matching.
167   */
168  public String getOrderingMatchingRuleNameOrOID()
169  {
170    final String name = getOrderingMatchingRuleName();
171    if (name == null)
172    {
173      return getOrderingMatchingRuleOID();
174    }
175    else
176    {
177      return name;
178    }
179  }
180
181
182
183  /**
184   * Retrieves the name for this matching rule when used to perform substring
185   * matching, if appropriate.
186   *
187   * @return  The name for this matching rule when used to perform substring
188   *          matching, or {@code null} if this matching rule is not intended
189   *          to be used for substring matching.
190   */
191  public abstract String getSubstringMatchingRuleName();
192
193
194
195  /**
196   * Retrieves the OID for this matching rule when used to perform substring
197   * matching, if appropriate.
198   *
199   * @return  The OID for this matching rule when used to perform substring
200   *          matching, or {@code null} if this matching rule is not intended
201   *          to be used for substring matching.
202   */
203  public abstract String getSubstringMatchingRuleOID();
204
205
206
207  /**
208   * Retrieves the name for this matching rule when used to perform substring
209   * matching if defined, or the OID if no name is available.
210   *
211   * @return  The name or OID for this matching rule when used to perform
212   *          substring matching, or {@code null} if this matching rule cannot
213   *          be used to perform equality matching.
214   */
215  public String getSubstringMatchingRuleNameOrOID()
216  {
217    final String name = getSubstringMatchingRuleName();
218    if (name == null)
219    {
220      return getSubstringMatchingRuleOID();
221    }
222    else
223    {
224      return name;
225    }
226  }
227
228
229
230  /**
231   * Indicates whether the provided values are equal to each other, according to
232   * the constraints of this matching rule.
233   *
234   * @param  value1  The first value for which to make the determination.
235   * @param  value2  The second value for which to make the determination.
236   *
237   * @return  {@code true} if the provided values are considered equal, or
238   *          {@code false} if not.
239   *
240   * @throws  LDAPException  If a problem occurs while making the determination,
241   *                         or if this matching rule does not support equality
242   *                         matching.
243   */
244  public abstract boolean valuesMatch(final ASN1OctetString value1,
245                                      final ASN1OctetString value2)
246         throws LDAPException;
247
248
249
250  /**
251   * Indicates whether the provided value matches the given substring assertion,
252   * according to the constraints of this matching rule.
253   *
254   * @param  value       The value for which to make the determination.
255   * @param  subInitial  The subInitial portion of the substring assertion, or
256   *                     {@code null} if there is no subInitial element.
257   * @param  subAny      The subAny elements of the substring assertion, or
258   *                     {@code null} if there are no subAny elements.
259   * @param  subFinal    The subFinal portion of the substring assertion, or
260   *                     {@code null} if there is no subFinal element.
261   *
262   * @return  {@code true} if the provided value matches the substring
263   *          assertion, or {@code false} if not.
264   *
265   * @throws  LDAPException  If a problem occurs while making the determination,
266   *                         or if this matching rule does not support substring
267   *                         matching.
268   */
269  public abstract boolean matchesSubstring(final ASN1OctetString value,
270                                           final ASN1OctetString subInitial,
271                                           final ASN1OctetString[] subAny,
272                                           final ASN1OctetString subFinal)
273         throws LDAPException;
274
275
276
277  /**
278   * Compares the provided values to determine their relative order in a sorted
279   * list.
280   *
281   * @param  value1  The first value to compare.
282   * @param  value2  The second value to compare.
283   *
284   * @return  A negative value if {@code value1} should come before
285   *          {@code value2} in a sorted list, a positive value if
286   *          {@code value1} should come after {@code value2} in a sorted list,
287   *          or zero if the values are equal or there is no distinction between
288   *          their orders in a sorted list.
289   *
290   * @throws  LDAPException  If a problem occurs while making the determination,
291   *                         or if this matching rule does not support ordering
292   *                         matching.
293   */
294  public abstract int compareValues(final ASN1OctetString value1,
295                                    final ASN1OctetString value2)
296         throws LDAPException;
297
298
299
300  /**
301   * Normalizes the provided value for easier matching.
302   *
303   * @param  value  The value to be normalized.
304   *
305   * @return  The normalized form of the provided value.
306   *
307   * @throws  LDAPException  If a problem occurs while normalizing the provided
308   *                         value.
309   */
310  public abstract ASN1OctetString normalize(final ASN1OctetString value)
311         throws LDAPException;
312
313
314
315  /**
316   * Normalizes the provided value for use as part of a substring assertion.
317   *
318   * @param  value          The value to be normalized for use as part of a
319   *                        substring assertion.
320   * @param  substringType  The substring assertion component type for the
321   *                        provided value.  It should be one of
322   *                        {@code SUBSTRING_TYPE_SUBINITIAL},
323   *                        {@code SUBSTRING_TYPE_SUBANY}, or
324   *                        {@code SUBSTRING_TYPE_SUBFINAL}.
325   *
326   * @return  The normalized form of the provided value.
327   *
328   * @throws  LDAPException  If a problem occurs while normalizing the provided
329   *                         value.
330   */
331  public abstract ASN1OctetString normalizeSubstring(
332                                       final ASN1OctetString value,
333                                       final byte substringType)
334         throws LDAPException;
335
336
337
338  /**
339   * Attempts to select the appropriate matching rule to use for equality
340   * matching against the specified attribute.  If an appropriate matching rule
341   * cannot be determined, then the default equality matching rule will be
342   * selected.
343   *
344   * @param  attrName  The name of the attribute to examine in the provided
345   *                   schema.
346   * @param  schema    The schema to examine to make the appropriate
347   *                   determination.  If this is {@code null}, then the default
348   *                   equality matching rule will be selected.
349   *
350   * @return  The selected matching rule.
351   */
352  public static MatchingRule selectEqualityMatchingRule(final String attrName,
353                                                        final Schema schema)
354  {
355    return selectEqualityMatchingRule(attrName, null, schema);
356  }
357
358
359
360  /**
361   * Attempts to select the appropriate matching rule to use for equality
362   * matching against the specified attribute.  If an appropriate matching rule
363   * cannot be determined, then the default equality matching rule will be
364   * selected.
365   *
366   * @param  attrName  The name of the attribute to examine in the provided
367   *                   schema.  It may be {@code null} if the matching rule
368   *                   should be selected using the matching rule ID.
369   * @param  ruleID    The OID of the desired matching rule.  It may be
370   *                   {@code null} if the matching rule should be selected only
371   *                   using the attribute name.  If a rule ID is provided, then
372   *                   it will be the only criteria used to select the matching
373   *                   rule.
374   * @param  schema    The schema to examine to make the appropriate
375   *                   determination.  If this is {@code null} and no rule ID
376   *                   was provided, then the default equality matching rule
377   *                   will be selected.
378   *
379   * @return  The selected matching rule.
380   */
381  public static MatchingRule selectEqualityMatchingRule(final String attrName,
382                                  final String ruleID, final Schema schema)
383  {
384    if (ruleID != null)
385    {
386      return selectEqualityMatchingRule(ruleID);
387    }
388
389    if ((attrName == null) || (schema == null))
390    {
391      return getDefaultEqualityMatchingRule();
392    }
393
394    final AttributeTypeDefinition attrType = schema.getAttributeType(attrName);
395    if (attrType == null)
396    {
397      return getDefaultEqualityMatchingRule();
398    }
399
400    final String mrName = attrType.getEqualityMatchingRule(schema);
401    if (mrName != null)
402    {
403      return selectEqualityMatchingRule(mrName);
404    }
405
406    final String syntaxOID = attrType.getBaseSyntaxOID(schema);
407    if (syntaxOID != null)
408    {
409      return selectMatchingRuleForSyntax(syntaxOID);
410    }
411
412    return getDefaultEqualityMatchingRule();
413  }
414
415
416
417  /**
418   * Attempts to select the appropriate matching rule to use for equality
419   * matching using the specified matching rule.  If an appropriate matching
420   * rule cannot be determined, then the default equality matching rule will be
421   * selected.
422   *
423   * @param  ruleID  The name or OID of the desired matching rule.
424   *
425   * @return  The selected matching rule.
426   */
427  public static MatchingRule selectEqualityMatchingRule(final String ruleID)
428  {
429    if ((ruleID == null) || (ruleID.length() == 0))
430    {
431      return getDefaultEqualityMatchingRule();
432    }
433
434    final String lowerName = toLowerCase(ruleID);
435    if (lowerName.equals(BooleanMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
436        lowerName.equals(BooleanMatchingRule.EQUALITY_RULE_OID))
437    {
438      return BooleanMatchingRule.getInstance();
439    }
440    else if (lowerName.equals(
441                  CaseExactStringMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
442             lowerName.equals(CaseExactStringMatchingRule.EQUALITY_RULE_OID) ||
443             lowerName.equals("caseexactia5match") ||
444             lowerName.equals("1.3.6.1.4.1.1466.109.114.1"))
445    {
446      return CaseExactStringMatchingRule.getInstance();
447    }
448    else if (lowerName.equals(
449                  CaseIgnoreListMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
450             lowerName.equals(CaseIgnoreListMatchingRule.EQUALITY_RULE_OID))
451    {
452      return CaseIgnoreListMatchingRule.getInstance();
453    }
454    else if (lowerName.equals(
455                  CaseIgnoreStringMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
456             lowerName.equals(CaseIgnoreStringMatchingRule.EQUALITY_RULE_OID) ||
457             lowerName.equals("caseignoreia5match") ||
458             lowerName.equals("1.3.6.1.4.1.1466.109.114.2"))
459    {
460      return CaseIgnoreStringMatchingRule.getInstance();
461    }
462    else if (lowerName.equals(
463                  DistinguishedNameMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
464             lowerName.equals(
465                  DistinguishedNameMatchingRule.EQUALITY_RULE_OID) ||
466             lowerName.equals("uniquemembermatch") ||
467             lowerName.equals("2.5.13.23"))
468    {
469      // NOTE -- Technically uniqueMember should use a name and optional UID
470      // matching rule, but the SDK doesn't currently provide one and the
471      // distinguished name matching rule should be sufficient the vast
472      // majority of the time.
473      return DistinguishedNameMatchingRule.getInstance();
474    }
475    else if (lowerName.equals(
476                  GeneralizedTimeMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
477             lowerName.equals(GeneralizedTimeMatchingRule.EQUALITY_RULE_OID))
478    {
479      return GeneralizedTimeMatchingRule.getInstance();
480    }
481    else if (lowerName.equals(IntegerMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
482             lowerName.equals(IntegerMatchingRule.EQUALITY_RULE_OID))
483    {
484      return IntegerMatchingRule.getInstance();
485    }
486    else if (lowerName.equals(
487                  NumericStringMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
488             lowerName.equals(NumericStringMatchingRule.EQUALITY_RULE_OID))
489    {
490      return NumericStringMatchingRule.getInstance();
491    }
492    else if (lowerName.equals(
493                  OctetStringMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
494             lowerName.equals(OctetStringMatchingRule.EQUALITY_RULE_OID))
495    {
496      return OctetStringMatchingRule.getInstance();
497    }
498    else if (lowerName.equals(
499                  TelephoneNumberMatchingRule.LOWER_EQUALITY_RULE_NAME) ||
500             lowerName.equals(TelephoneNumberMatchingRule.EQUALITY_RULE_OID))
501    {
502      return TelephoneNumberMatchingRule.getInstance();
503    }
504    else
505    {
506      return getDefaultEqualityMatchingRule();
507    }
508  }
509
510
511
512  /**
513   * Retrieves the default matching rule that will be used for equality matching
514   * if no other matching rule is specified or available.  The rule returned
515   * will perform case-ignore string matching.
516   *
517   * @return  The default matching rule that will be used for equality matching
518   *          if no other matching rule is specified or available.
519   */
520  public static MatchingRule getDefaultEqualityMatchingRule()
521  {
522    return CaseIgnoreStringMatchingRule.getInstance();
523  }
524
525
526
527  /**
528   * Attempts to select the appropriate matching rule to use for ordering
529   * matching against the specified attribute.  If an appropriate matching rule
530   * cannot be determined, then the default ordering matching rule will be
531   * selected.
532   *
533   * @param  attrName  The name of the attribute to examine in the provided
534   *                   schema.
535   * @param  schema    The schema to examine to make the appropriate
536   *                   determination.  If this is {@code null}, then the default
537   *                   ordering matching rule will be selected.
538   *
539   * @return  The selected matching rule.
540   */
541  public static MatchingRule selectOrderingMatchingRule(final String attrName,
542                                                        final Schema schema)
543  {
544    return selectOrderingMatchingRule(attrName, null, schema);
545  }
546
547
548
549  /**
550   * Attempts to select the appropriate matching rule to use for ordering
551   * matching against the specified attribute.  If an appropriate matching rule
552   * cannot be determined, then the default ordering matching rule will be
553   * selected.
554   *
555   * @param  attrName  The name of the attribute to examine in the provided
556   *                   schema.  It may be {@code null} if the matching rule
557   *                   should be selected using the matching rule ID.
558   * @param  ruleID    The OID of the desired matching rule.  It may be
559   *                   {@code null} if the matching rule should be selected only
560   *                   using the attribute name.  If a rule ID is provided, then
561   *                   it will be the only criteria used to select the matching
562   *                   rule.
563   * @param  schema    The schema to examine to make the appropriate
564   *                   determination.  If this is {@code null} and no rule ID
565   *                   was provided, then the default ordering matching rule
566   *                   will be selected.
567   *
568   * @return  The selected matching rule.
569   */
570  public static MatchingRule selectOrderingMatchingRule(final String attrName,
571                                                        final String ruleID,
572                                                        final Schema schema)
573  {
574    if (ruleID != null)
575    {
576      return selectOrderingMatchingRule(ruleID);
577    }
578
579    if ((attrName == null) || (schema == null))
580    {
581      return getDefaultOrderingMatchingRule();
582    }
583
584    final AttributeTypeDefinition attrType = schema.getAttributeType(attrName);
585    if (attrType == null)
586    {
587      return getDefaultOrderingMatchingRule();
588    }
589
590    final String mrName = attrType.getOrderingMatchingRule(schema);
591    if (mrName != null)
592    {
593      return selectOrderingMatchingRule(mrName);
594    }
595
596    final String syntaxOID = attrType.getBaseSyntaxOID(schema);
597    if (syntaxOID != null)
598    {
599      return selectMatchingRuleForSyntax(syntaxOID);
600    }
601
602    return getDefaultOrderingMatchingRule();
603  }
604
605
606
607  /**
608   * Attempts to select the appropriate matching rule to use for ordering
609   * matching using the specified matching rule.  If an appropriate matching
610   * rule cannot be determined, then the default ordering matching rule will be
611   * selected.
612   *
613   * @param  ruleID  The name or OID of the desired matching rule.
614   *
615   * @return  The selected matching rule.
616   */
617  public static MatchingRule selectOrderingMatchingRule(final String ruleID)
618  {
619    if ((ruleID == null) || (ruleID.length() == 0))
620    {
621      return getDefaultOrderingMatchingRule();
622    }
623
624    final String lowerName = toLowerCase(ruleID);
625    if (lowerName.equals(
626             CaseExactStringMatchingRule.LOWER_ORDERING_RULE_NAME) ||
627        lowerName.equals(CaseExactStringMatchingRule.ORDERING_RULE_OID))
628    {
629      return CaseExactStringMatchingRule.getInstance();
630    }
631    else if (lowerName.equals(
632                  CaseIgnoreStringMatchingRule.LOWER_ORDERING_RULE_NAME) ||
633             lowerName.equals(CaseIgnoreStringMatchingRule.ORDERING_RULE_OID))
634    {
635      return CaseIgnoreStringMatchingRule.getInstance();
636    }
637    else if (lowerName.equals(
638                  GeneralizedTimeMatchingRule.LOWER_ORDERING_RULE_NAME) ||
639             lowerName.equals(GeneralizedTimeMatchingRule.ORDERING_RULE_OID))
640    {
641      return GeneralizedTimeMatchingRule.getInstance();
642    }
643    else if (lowerName.equals(IntegerMatchingRule.LOWER_ORDERING_RULE_NAME) ||
644             lowerName.equals(IntegerMatchingRule.ORDERING_RULE_OID))
645    {
646      return IntegerMatchingRule.getInstance();
647    }
648    else if (lowerName.equals(
649                  NumericStringMatchingRule.LOWER_ORDERING_RULE_NAME) ||
650             lowerName.equals(NumericStringMatchingRule.ORDERING_RULE_OID))
651    {
652      return NumericStringMatchingRule.getInstance();
653    }
654    else if (lowerName.equals(
655                  OctetStringMatchingRule.LOWER_ORDERING_RULE_NAME) ||
656             lowerName.equals(OctetStringMatchingRule.ORDERING_RULE_OID))
657    {
658      return OctetStringMatchingRule.getInstance();
659    }
660    else
661    {
662      return getDefaultOrderingMatchingRule();
663    }
664  }
665
666
667
668  /**
669   * Retrieves the default matching rule that will be used for ordering matching
670   * if no other matching rule is specified or available.  The rule returned
671   * will perform case-ignore string matching.
672   *
673   * @return  The default matching rule that will be used for ordering matching
674   *          if no other matching rule is specified or available.
675   */
676  public static MatchingRule getDefaultOrderingMatchingRule()
677  {
678    return CaseIgnoreStringMatchingRule.getInstance();
679  }
680
681
682
683  /**
684   * Attempts to select the appropriate matching rule to use for substring
685   * matching against the specified attribute.  If an appropriate matching rule
686   * cannot be determined, then the default substring matching rule will be
687   * selected.
688   *
689   * @param  attrName  The name of the attribute to examine in the provided
690   *                   schema.
691   * @param  schema    The schema to examine to make the appropriate
692   *                   determination.  If this is {@code null}, then the default
693   *                   substring matching rule will be selected.
694   *
695   * @return  The selected matching rule.
696   */
697  public static MatchingRule selectSubstringMatchingRule(final String attrName,
698                                                         final Schema schema)
699  {
700    return selectSubstringMatchingRule(attrName, null, schema);
701  }
702
703
704
705  /**
706   * Attempts to select the appropriate matching rule to use for substring
707   * matching against the specified attribute.  If an appropriate matching rule
708   * cannot be determined, then the default substring matching rule will be
709   * selected.
710   *
711   * @param  attrName  The name of the attribute to examine in the provided
712   *                   schema.  It may be {@code null} if the matching rule
713   *                   should be selected using the matching rule ID.
714   * @param  ruleID    The OID of the desired matching rule.  It may be
715   *                   {@code null} if the matching rule should be selected only
716   *                   using the attribute name.  If a rule ID is provided, then
717   *                   it will be the only criteria used to select the matching
718   *                   rule.
719   * @param  schema    The schema to examine to make the appropriate
720   *                   determination.  If this is {@code null} and no rule ID
721   *                   was provided, then the default substring matching rule
722   *                   will be selected.
723   *
724   * @return  The selected matching rule.
725   */
726  public static MatchingRule selectSubstringMatchingRule(final String attrName,
727                                                         final String ruleID,
728                                                         final Schema schema)
729  {
730    if (ruleID != null)
731    {
732      return selectSubstringMatchingRule(ruleID);
733    }
734
735    if ((attrName == null) || (schema == null))
736    {
737      return getDefaultSubstringMatchingRule();
738    }
739
740    final AttributeTypeDefinition attrType = schema.getAttributeType(attrName);
741    if (attrType == null)
742    {
743      return getDefaultSubstringMatchingRule();
744    }
745
746    final String mrName = attrType.getSubstringMatchingRule(schema);
747    if (mrName != null)
748    {
749      return selectSubstringMatchingRule(mrName);
750    }
751
752    final String syntaxOID = attrType.getBaseSyntaxOID(schema);
753    if (syntaxOID != null)
754    {
755      return selectMatchingRuleForSyntax(syntaxOID);
756    }
757
758    return getDefaultSubstringMatchingRule();
759  }
760
761
762
763  /**
764   * Attempts to select the appropriate matching rule to use for substring
765   * matching using the specified matching rule.  If an appropriate matching
766   * rule cannot be determined, then the default substring matching rule will be
767   * selected.
768   *
769   * @param  ruleID  The name or OID of the desired matching rule.
770   *
771   * @return  The selected matching rule.
772   */
773  public static MatchingRule selectSubstringMatchingRule(final String ruleID)
774  {
775    if ((ruleID == null) || (ruleID.length() == 0))
776    {
777      return getDefaultSubstringMatchingRule();
778    }
779
780    final String lowerName = toLowerCase(ruleID);
781    if (lowerName.equals(
782             CaseExactStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
783        lowerName.equals(CaseExactStringMatchingRule.SUBSTRING_RULE_OID) ||
784        lowerName.equals("caseexactia5substringsmatch"))
785    {
786      return CaseExactStringMatchingRule.getInstance();
787    }
788    else if (lowerName.equals(
789                  CaseIgnoreListMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
790             lowerName.equals(CaseIgnoreListMatchingRule.SUBSTRING_RULE_OID))
791    {
792      return CaseIgnoreListMatchingRule.getInstance();
793    }
794    else if (lowerName.equals(
795                  CaseIgnoreStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
796             lowerName.equals(
797                  CaseIgnoreStringMatchingRule.SUBSTRING_RULE_OID) ||
798             lowerName.equals("caseignoreia5substringsmatch") ||
799             lowerName.equals("1.3.6.1.4.1.1466.109.114.3"))
800    {
801      return CaseIgnoreStringMatchingRule.getInstance();
802    }
803    else if (lowerName.equals(
804                  NumericStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
805             lowerName.equals(NumericStringMatchingRule.SUBSTRING_RULE_OID))
806    {
807      return NumericStringMatchingRule.getInstance();
808    }
809    else if (lowerName.equals(
810                  OctetStringMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
811             lowerName.equals(OctetStringMatchingRule.SUBSTRING_RULE_OID))
812    {
813      return OctetStringMatchingRule.getInstance();
814    }
815    else if (lowerName.equals(
816                  TelephoneNumberMatchingRule.LOWER_SUBSTRING_RULE_NAME) ||
817             lowerName.equals(TelephoneNumberMatchingRule.SUBSTRING_RULE_OID))
818    {
819      return TelephoneNumberMatchingRule.getInstance();
820    }
821    else
822    {
823      return getDefaultSubstringMatchingRule();
824    }
825  }
826
827
828
829  /**
830   * Retrieves the default matching rule that will be used for substring
831   * matching if no other matching rule is specified or available.  The rule
832   * returned will perform case-ignore string matching.
833   *
834   * @return  The default matching rule that will be used for substring matching
835   *          if no other matching rule is specified or available.
836   */
837  public static MatchingRule getDefaultSubstringMatchingRule()
838  {
839    return CaseIgnoreStringMatchingRule.getInstance();
840  }
841
842
843
844  /**
845   * Attempts to select the appropriate matching rule for use with the syntax
846   * with the specified OID.  If an appropriate matching rule cannot be
847   * determined, then the case-ignore string matching rule will be selected.
848   *
849   * @param  syntaxOID  The OID of the attribute syntax for which to make the
850   *                    determination.
851   *
852   * @return  The selected matching rule.
853   */
854  public static MatchingRule selectMatchingRuleForSyntax(final String syntaxOID)
855  {
856    if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.7"))
857    {
858      return BooleanMatchingRule.getInstance();
859    }
860    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.41")) // Postal addr.
861    {
862      return CaseIgnoreListMatchingRule.getInstance();
863    }
864    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.12") ||
865         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.34")) // name&optional UID
866    {
867      return DistinguishedNameMatchingRule.getInstance();
868    }
869    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.24") ||
870         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.53")) // UTC time
871    {
872      return GeneralizedTimeMatchingRule.getInstance();
873    }
874    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.27"))
875    {
876      return IntegerMatchingRule.getInstance();
877    }
878    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.36"))
879    {
880      return NumericStringMatchingRule.getInstance();
881    }
882    else if (syntaxOID.equals("1.3.6.1.4.1.4203.1.1.2") || // auth password
883         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.5") || // binary
884         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.8") || // certificate
885         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.9") || // cert list
886         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.10") || // cert pair
887         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.28") || // JPEG
888         syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.40")) // octet string
889    {
890      return OctetStringMatchingRule.getInstance();
891    }
892    else if (syntaxOID.equals("1.3.6.1.4.1.1466.115.121.1.50"))
893    {
894      return TelephoneNumberMatchingRule.getInstance();
895    }
896    else
897    {
898      return CaseIgnoreStringMatchingRule.getInstance();
899    }
900  }
901}