001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.schema;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.Arrays;
033    
034    import org.opends.server.admin.std.server.EqualityMatchingRuleCfg;
035    import org.opends.server.api.EqualityMatchingRule;
036    import org.opends.server.config.ConfigException;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.types.ByteString;
040    import org.opends.server.types.DirectoryException;
041    import org.opends.server.types.InitializationException;
042    import org.opends.server.types.ResultCode;
043    
044    import static org.opends.messages.SchemaMessages.*;
045    import static org.opends.server.schema.SchemaConstants.*;
046    import org.opends.server.loggers.ErrorLogger;
047    
048    
049    /**
050     * This class defines the integerMatch matching rule defined in X.520 and
051     * referenced in RFC 2252.
052     */
053    public class IntegerEqualityMatchingRule
054           extends EqualityMatchingRule
055    {
056      /**
057       * Creates a new instance of this integerMatch matching rule.
058       */
059      public IntegerEqualityMatchingRule()
060      {
061        super();
062      }
063    
064    
065    
066      /**
067       * {@inheritDoc}
068       */
069      public void initializeMatchingRule(EqualityMatchingRuleCfg configuration)
070             throws ConfigException, InitializationException
071      {
072        // No initialization is required.
073      }
074    
075    
076    
077      /**
078       * Retrieves the common name for this matching rule.
079       *
080       * @return  The common name for this matching rule, or <CODE>null</CODE> if
081       * it does not have a name.
082       */
083      public String getName()
084      {
085        return EMR_INTEGER_NAME;
086      }
087    
088    
089    
090      /**
091       * Retrieves the OID for this matching rule.
092       *
093       * @return  The OID for this matching rule.
094       */
095      public String getOID()
096      {
097        return EMR_INTEGER_OID;
098      }
099    
100    
101    
102      /**
103       * Retrieves the description for this matching rule.
104       *
105       * @return  The description for this matching rule, or <CODE>null</CODE> if
106       *          there is none.
107       */
108      public String getDescription()
109      {
110        // There is no standard description for this matching rule.
111        return null;
112      }
113    
114    
115    
116      /**
117       * Retrieves the OID of the syntax with which this matching rule is
118       * associated.
119       *
120       * @return  The OID of the syntax with which this matching rule is associated.
121       */
122      public String getSyntaxOID()
123      {
124        return SYNTAX_INTEGER_OID;
125      }
126    
127    
128    
129      /**
130       * Retrieves the normalized form of the provided value, which is best suited
131       * for efficiently performing matching operations on that value.
132       *
133       * @param  value  The value to be normalized.
134       *
135       * @return  The normalized version of the provided value.
136       *
137       * @throws  DirectoryException  If the provided value is invalid according to
138       *                              the associated attribute syntax.
139       */
140      public ByteString normalizeValue(ByteString value)
141             throws DirectoryException
142      {
143        byte[] valueBytes = value.value();
144    
145        int length = valueBytes.length;
146        StringBuilder buffer = new StringBuilder(length);
147    
148        boolean logged = false;
149        for (int i=0; i < length; i++)
150        {
151          switch (valueBytes[i])
152          {
153            case '0':
154              switch (buffer.length())
155              {
156                case 0:
157                  // This is only OK if the value is zero
158                  if (i == (length-1))
159                  {
160                    buffer.append("0");
161                  }
162                  else
163                  {
164                    Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
165                            value.stringValue());
166    
167                    switch (DirectoryServer.getSyntaxEnforcementPolicy())
168                    {
169                      case REJECT:
170                        throw new DirectoryException(
171                                      ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
172                      case WARN:
173                        if (! logged)
174                        {
175                          logged = true;
176                          ErrorLogger.logError(message);
177                        }
178                        break;
179                    }
180                  }
181                  break;
182                case 1:
183                  // This is OK as long as the first character isn't a dash.
184                  if (buffer.charAt(0) == '-')
185                  {
186                    Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
187                            value.stringValue());
188    
189                    switch (DirectoryServer.getSyntaxEnforcementPolicy())
190                    {
191                      case REJECT:
192                        throw new DirectoryException(
193                                      ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
194                      case WARN:
195                        if (! logged)
196                        {
197                          logged = true;
198                          ErrorLogger.logError(message);
199                        }
200                        break;
201                    }
202                  }
203                  else
204                  {
205                    buffer.append("0");
206                  }
207                  break;
208                default:
209                  // This is always fine.
210                  buffer.append("0");
211                  break;
212              }
213              break;
214            case '1':
215              buffer.append('1');
216              break;
217            case '2':
218              buffer.append('2');
219              break;
220            case '3':
221              buffer.append('3');
222              break;
223            case '4':
224              buffer.append('4');
225              break;
226            case '5':
227              buffer.append('5');
228              break;
229            case '6':
230              buffer.append('6');
231              break;
232            case '7':
233              buffer.append('7');
234              break;
235            case '8':
236              buffer.append('8');
237              break;
238            case '9':
239              buffer.append('9');
240              break;
241            case '-':
242              // This is only OK if the buffer is empty.
243              if (buffer.length() == 0)
244              {
245                buffer.append("-");
246              }
247              else
248              {
249                Message message = WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH.get(
250                        value.stringValue());
251    
252                switch (DirectoryServer.getSyntaxEnforcementPolicy())
253                {
254                  case REJECT:
255                    throw new DirectoryException(
256                                   ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
257                  case WARN:
258                    if (! logged)
259                    {
260                      logged = true;
261                      ErrorLogger.logError(message);
262                    }
263                    break;
264                }
265              }
266              break;
267            default:
268              Message message = WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
269                      value.stringValue(),
270                      ((char) valueBytes[i]), i);
271              switch (DirectoryServer.getSyntaxEnforcementPolicy())
272              {
273                case REJECT:
274                  throw new DirectoryException(
275                                 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
276                case WARN:
277                  if (! logged)
278                  {
279                    logged = true;
280                    ErrorLogger.logError(message);
281                  }
282                  break;
283              }
284          }
285        }
286    
287        if (buffer.length() == 0)
288        {
289          Message message = WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE.get(
290                  value.stringValue());
291    
292          switch (DirectoryServer.getSyntaxEnforcementPolicy())
293          {
294            case REJECT:
295              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
296                                           message);
297    
298            case WARN:
299              if (! logged)
300              {
301                logged = true;
302                ErrorLogger.logError(message);
303              }
304    
305              buffer.append("0");
306              break;
307    
308            default:
309              buffer.append("0");
310              break;
311          }
312        }
313        else if ((buffer.length() == 1) && (buffer.charAt(0) == '-'))
314        {
315          Message message = WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE.get(
316                  value.stringValue());
317          switch (DirectoryServer.getSyntaxEnforcementPolicy())
318          {
319            case REJECT:
320              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
321                                           message);
322    
323            case WARN:
324              if (! logged)
325              {
326                logged = true;
327                ErrorLogger.logError(message);
328              }
329    
330              buffer.setCharAt(0, '0');
331              break;
332    
333            default:
334              buffer.setCharAt(0, '0');
335              break;
336          }
337        }
338    
339        return new ASN1OctetString(buffer.toString());
340      }
341    
342    
343    
344      /**
345       * Indicates whether the two provided normalized values are equal to each
346       * other.
347       *
348       * @param  value1  The normalized form of the first value to compare.
349       * @param  value2  The normalized form of the second value to compare.
350       *
351       * @return  <CODE>true</CODE> if the provided values are equal, or
352       *          <CODE>false</CODE> if not.
353       */
354      public boolean areEqual(ByteString value1, ByteString value2)
355      {
356        // Since the values are already normalized, we just need to compare the
357        // associated byte arrays.
358        return Arrays.equals(value1.value(), value2.value());
359      }
360    }
361