001    /*
002     * Copyright 2008-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 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     */
021    package com.unboundid.ldap.matchingrules;
022    
023    
024    
025    import com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.ldap.sdk.LDAPException;
027    import com.unboundid.ldap.sdk.ResultCode;
028    import com.unboundid.util.ThreadSafety;
029    import com.unboundid.util.ThreadSafetyLevel;
030    
031    import static com.unboundid.ldap.matchingrules.MatchingRuleMessages.*;
032    import static com.unboundid.util.StaticUtils.*;
033    
034    
035    
036    /**
037     * This class provides an implementation of a matching rule that allows strings
038     * consisting of numeric digits and spaces.  Spaces will be considered
039     * insignificant for matching purposes.
040     */
041    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
042    public final class NumericStringMatchingRule
043           extends SimpleMatchingRule
044    {
045      /**
046       * The singleton instance that will be returned from the {@code getInstance}
047       * method.
048       */
049      private static final NumericStringMatchingRule INSTANCE =
050           new NumericStringMatchingRule();
051    
052    
053    
054      /**
055       * The name for the numericStringMatch equality matching rule.
056       */
057      public static final String EQUALITY_RULE_NAME = "numericStringMatch";
058    
059    
060    
061      /**
062       * The name for the numericStringMatch equality matching rule, formatted in
063       * all lowercase characters.
064       */
065      static final String LOWER_EQUALITY_RULE_NAME =
066           toLowerCase(EQUALITY_RULE_NAME);
067    
068    
069    
070      /**
071       * The OID for the numericStringMatch equality matching rule.
072       */
073      public static final String EQUALITY_RULE_OID = "2.5.13.8";
074    
075    
076    
077      /**
078       * The name for the numericStringOrderingMatch ordering matching rule.
079       */
080      public static final String ORDERING_RULE_NAME = "numericStringOrderingMatch";
081    
082    
083    
084      /**
085       * The name for the numericStringOrderingMatch ordering matching rule,
086       * formatted in all lowercase characters.
087       */
088      static final String LOWER_ORDERING_RULE_NAME =
089           toLowerCase(ORDERING_RULE_NAME);
090    
091    
092    
093      /**
094       * The OID for the numericStringOrderingMatch ordering matching rule.
095       */
096      public static final String ORDERING_RULE_OID = "2.5.13.9";
097    
098    
099    
100      /**
101       * The name for the numericStringSubstringsMatch substring matching rule.
102       */
103      public static final String SUBSTRING_RULE_NAME =
104           "numericStringSubstringsMatch";
105    
106    
107    
108      /**
109       * The name for the numericStringSubstringsMatch substring matching rule,
110       * formatted in all lowercase characters.
111       */
112      static final String LOWER_SUBSTRING_RULE_NAME =
113           toLowerCase(SUBSTRING_RULE_NAME);
114    
115    
116    
117      /**
118       * The OID for the numericStringSubstringsMatch substring matching rule.
119       */
120      public static final String SUBSTRING_RULE_OID = "2.5.13.10";
121    
122    
123    
124      /**
125       * The serial version UID for this serializable class.
126       */
127      private static final long serialVersionUID = -898484312052746321L;
128    
129    
130    
131      /**
132       * Creates a new instance of this numeric string matching rule.
133       */
134      public NumericStringMatchingRule()
135      {
136        // No implementation is required.
137      }
138    
139    
140    
141      /**
142       * Retrieves a singleton instance of this matching rule.
143       *
144       * @return  A singleton instance of this matching rule.
145       */
146      public static NumericStringMatchingRule getInstance()
147      {
148        return INSTANCE;
149      }
150    
151    
152    
153      /**
154       * {@inheritDoc}
155       */
156      @Override()
157      public String getEqualityMatchingRuleName()
158      {
159        return EQUALITY_RULE_NAME;
160      }
161    
162    
163    
164      /**
165       * {@inheritDoc}
166       */
167      @Override()
168      public String getEqualityMatchingRuleOID()
169      {
170        return EQUALITY_RULE_OID;
171      }
172    
173    
174    
175      /**
176       * {@inheritDoc}
177       */
178      @Override()
179      public String getOrderingMatchingRuleName()
180      {
181        return ORDERING_RULE_NAME;
182      }
183    
184    
185    
186      /**
187       * {@inheritDoc}
188       */
189      @Override()
190      public String getOrderingMatchingRuleOID()
191      {
192        return ORDERING_RULE_OID;
193      }
194    
195    
196    
197      /**
198       * {@inheritDoc}
199       */
200      @Override()
201      public String getSubstringMatchingRuleName()
202      {
203        return SUBSTRING_RULE_NAME;
204      }
205    
206    
207    
208      /**
209       * {@inheritDoc}
210       */
211      @Override()
212      public String getSubstringMatchingRuleOID()
213      {
214        return SUBSTRING_RULE_OID;
215      }
216    
217    
218    
219      /**
220       * {@inheritDoc}
221       */
222      @Override()
223      public ASN1OctetString normalize(final ASN1OctetString value)
224             throws LDAPException
225      {
226        // The value may already be normalized, so optimize behavior for that
227        // possibility.
228        int numSpaces = 0;
229        final byte[] valueBytes = value.getValue();
230        for (int i=0; i < valueBytes.length; i++)
231        {
232          if (valueBytes[i] == ' ')
233          {
234            numSpaces++;
235          }
236          else if ((valueBytes[i] < '0') || (valueBytes[i] > '9'))
237          {
238            throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
239                                    ERR_NUMERIC_STRING_INVALID_CHARACTER.get(i));
240          }
241        }
242    
243        if (numSpaces == 0)
244        {
245          return value;
246        }
247    
248        int pos = 0;
249        final byte[] returnBytes = new byte[valueBytes.length-numSpaces];
250        for (final byte b : valueBytes)
251        {
252          if (b != ' ')
253          {
254            returnBytes[pos++] = b;
255          }
256        }
257    
258        return new ASN1OctetString(returnBytes);
259      }
260    
261    
262    
263      /**
264       * {@inheritDoc}
265       */
266      @Override()
267      public ASN1OctetString normalizeSubstring(final ASN1OctetString value,
268                                                final byte substringType)
269             throws LDAPException
270      {
271        return normalize(value);
272      }
273    }