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 org.opends.server.admin.std.server.AttributeSyntaxCfg;
033    import org.opends.server.api.ApproximateMatchingRule;
034    import org.opends.server.api.AttributeSyntax;
035    import org.opends.server.api.AttributeValueDecoder;
036    import org.opends.server.api.EqualityMatchingRule;
037    import org.opends.server.api.OrderingMatchingRule;
038    import org.opends.server.api.SubstringMatchingRule;
039    import org.opends.server.config.ConfigException;
040    import org.opends.server.core.DirectoryServer;
041    import org.opends.server.types.AttributeValue;
042    import org.opends.server.types.ByteString;
043    import org.opends.server.types.DirectoryException;
044    
045    
046    import org.opends.server.types.ResultCode;
047    
048    import static org.opends.server.loggers.ErrorLogger.*;
049    import static org.opends.messages.SchemaMessages.*;
050    import org.opends.messages.MessageBuilder;
051    import static org.opends.server.schema.SchemaConstants.*;
052    
053    
054    /**
055     * This class defines the integer attribute syntax, which holds an
056     * arbitrarily-long integer value.  Equality, ordering, and substring matching
057     * will be allowed by default.
058     */
059    public class IntegerSyntax
060           extends AttributeSyntax<AttributeSyntaxCfg>
061    {
062      // The default equality matching rule for this syntax.
063      private EqualityMatchingRule defaultEqualityMatchingRule;
064    
065      // The default ordering matching rule for this syntax.
066      private OrderingMatchingRule defaultOrderingMatchingRule;
067    
068      // The default substring matching rule for this syntax.
069      private SubstringMatchingRule defaultSubstringMatchingRule;
070    
071    
072    
073      /**
074       * An {@link Integer} attribute value decoder for this syntax.
075       */
076      public static final AttributeValueDecoder<Integer> DECODER =
077        new AttributeValueDecoder<Integer>()
078      {
079        /**
080         * {@inheritDoc}
081         */
082        public Integer decode(AttributeValue value) throws DirectoryException
083        {
084          ByteString nvalue = value.getNormalizedValue();
085          try
086          {
087            return Integer.valueOf(nvalue.stringValue());
088          }
089          catch (NumberFormatException e)
090          {
091            Message message =
092                WARN_ATTR_SYNTAX_ILLEGAL_INTEGER.get(nvalue.stringValue());
093            throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
094                message);
095          }
096        }
097      };
098    
099    
100    
101      /**
102       * Creates a new instance of this syntax. Note that the only thing
103       * that should be done here is to invoke the default constructor for
104       * the superclass. All initialization should be performed in the
105       * <CODE>initializeSyntax</CODE> method.
106       */
107      public IntegerSyntax()
108      {
109        super();
110      }
111    
112    
113    
114      /**
115       * {@inheritDoc}
116       */
117      public void initializeSyntax(AttributeSyntaxCfg configuration)
118             throws ConfigException
119      {
120        defaultEqualityMatchingRule =
121             DirectoryServer.getEqualityMatchingRule(EMR_INTEGER_OID);
122        if (defaultEqualityMatchingRule == null)
123        {
124          logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
125              EMR_INTEGER_OID, SYNTAX_INTEGER_NAME));
126        }
127    
128        defaultOrderingMatchingRule =
129             DirectoryServer.getOrderingMatchingRule(OMR_INTEGER_OID);
130        if (defaultOrderingMatchingRule == null)
131        {
132          logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
133              OMR_INTEGER_OID, SYNTAX_INTEGER_NAME));
134        }
135    
136        defaultSubstringMatchingRule =
137             DirectoryServer.getSubstringMatchingRule(SMR_CASE_EXACT_OID);
138        if (defaultSubstringMatchingRule == null)
139        {
140          logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
141              SMR_CASE_EXACT_OID, SYNTAX_INTEGER_NAME));
142        }
143      }
144    
145    
146    
147      /**
148       * Retrieves the common name for this attribute syntax.
149       *
150       * @return  The common name for this attribute syntax.
151       */
152      public String getSyntaxName()
153      {
154        return SYNTAX_INTEGER_NAME;
155      }
156    
157    
158    
159      /**
160       * Retrieves the OID for this attribute syntax.
161       *
162       * @return  The OID for this attribute syntax.
163       */
164      public String getOID()
165      {
166        return SYNTAX_INTEGER_OID;
167      }
168    
169    
170    
171      /**
172       * Retrieves a description for this attribute syntax.
173       *
174       * @return  A description for this attribute syntax.
175       */
176      public String getDescription()
177      {
178        return SYNTAX_INTEGER_DESCRIPTION;
179      }
180    
181    
182    
183      /**
184       * Retrieves the default equality matching rule that will be used for
185       * attributes with this syntax.
186       *
187       * @return  The default equality matching rule that will be used for
188       *          attributes with this syntax, or <CODE>null</CODE> if equality
189       *          matches will not be allowed for this type by default.
190       */
191      public EqualityMatchingRule getEqualityMatchingRule()
192      {
193        return defaultEqualityMatchingRule;
194      }
195    
196    
197    
198      /**
199       * Retrieves the default ordering matching rule that will be used for
200       * attributes with this syntax.
201       *
202       * @return  The default ordering matching rule that will be used for
203       *          attributes with this syntax, or <CODE>null</CODE> if ordering
204       *          matches will not be allowed for this type by default.
205       */
206      public OrderingMatchingRule getOrderingMatchingRule()
207      {
208        return defaultOrderingMatchingRule;
209      }
210    
211    
212    
213      /**
214       * Retrieves the default substring matching rule that will be used for
215       * attributes with this syntax.
216       *
217       * @return  The default substring matching rule that will be used for
218       *          attributes with this syntax, or <CODE>null</CODE> if substring
219       *          matches will not be allowed for this type by default.
220       */
221      public SubstringMatchingRule getSubstringMatchingRule()
222      {
223        return defaultSubstringMatchingRule;
224      }
225    
226    
227    
228      /**
229       * Retrieves the default approximate matching rule that will be used for
230       * attributes with this syntax.
231       *
232       * @return  The default approximate matching rule that will be used for
233       *          attributes with this syntax, or <CODE>null</CODE> if approximate
234       *          matches will not be allowed for this type by default.
235       */
236      public ApproximateMatchingRule getApproximateMatchingRule()
237      {
238        // There is no approximate matching rule by default.
239        return null;
240      }
241    
242    
243    
244      /**
245       * Indicates whether the provided value is acceptable for use in an attribute
246       * with this syntax.  If it is not, then the reason may be appended to the
247       * provided buffer.
248       *
249       * @param  value          The value for which to make the determination.
250       * @param  invalidReason  The buffer to which the invalid reason should be
251       *                        appended.
252       *
253       * @return  <CODE>true</CODE> if the provided value is acceptable for use with
254       *          this syntax, or <CODE>false</CODE> if not.
255       */
256      public boolean valueIsAcceptable(ByteString value,
257                                       MessageBuilder invalidReason)
258      {
259        String valueString = value.stringValue();
260        int    length      = valueString.length();
261    
262        if (length == 0)
263        {
264          invalidReason.append(
265                  WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE.get(valueString));
266          return false;
267        }
268        else if (length == 1)
269        {
270          switch (valueString.charAt(0))
271          {
272            case '0':
273            case '1':
274            case '2':
275            case '3':
276            case '4':
277            case '5':
278            case '6':
279            case '7':
280            case '8':
281            case '9':
282              return true;
283            case '-':
284              invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE.get(
285                      valueString));
286              return false;
287            default:
288              invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
289                      valueString,
290                      valueString.charAt(0), 0));
291              return false;
292          }
293        }
294        else
295        {
296          boolean negative = false;
297    
298          switch (valueString.charAt(0))
299          {
300            case '0':
301              invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
302                      valueString));
303              return false;
304            case '1':
305            case '2':
306            case '3':
307            case '4':
308            case '5':
309            case '6':
310            case '7':
311            case '8':
312            case '9':
313              // These are all fine.
314              break;
315            case '-':
316              // This is fine too.
317              negative = true;
318              break;
319            default:
320              invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
321                      valueString,
322                      valueString.charAt(0), 0));
323              return false;
324          }
325    
326          switch (valueString.charAt(1))
327          {
328            case '0':
329              // This is fine as long as the value isn't negative.
330              if (negative)
331              {
332                invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
333                        valueString));
334                return false;
335              }
336              break;
337            case '1':
338            case '2':
339            case '3':
340            case '4':
341            case '5':
342            case '6':
343            case '7':
344            case '8':
345            case '9':
346              // These are all fine.
347              break;
348            default:
349              invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
350                      valueString,
351                      valueString.charAt(0), 0));
352              return false;
353          }
354    
355          for (int i=2; i < length; i++)
356          {
357            switch (valueString.charAt(i))
358            {
359              case '0':
360              case '1':
361              case '2':
362              case '3':
363              case '4':
364              case '5':
365              case '6':
366              case '7':
367              case '8':
368              case '9':
369                // These are all fine.
370                break;
371              default:
372                invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
373                        valueString,
374                        valueString.charAt(0), 0));
375                return false;
376            }
377          }
378    
379          return true;
380        }
381      }
382    }
383