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.OrderingMatchingRuleCfg;
033    import org.opends.server.api.OrderingMatchingRule;
034    import org.opends.server.config.ConfigException;
035    import org.opends.server.core.DirectoryServer;
036    import org.opends.server.protocols.asn1.ASN1OctetString;
037    import org.opends.server.types.ByteString;
038    import org.opends.server.types.DirectoryException;
039    import org.opends.server.types.InitializationException;
040    import org.opends.server.types.ResultCode;
041    
042    import static org.opends.messages.SchemaMessages.*;
043    import static org.opends.server.schema.SchemaConstants.*;
044    import org.opends.server.loggers.ErrorLogger;
045    
046    
047    /**
048     * This class defines the uuidOrderingMatch matching rule defined in RFC 4530.
049     * This will be the default ordering matching rule for the UUID syntax.
050     */
051    public class UUIDOrderingMatchingRule
052           extends OrderingMatchingRule
053    {
054      /**
055       * The serial version identifier required to satisfy the compiler because this
056       * class implements the <CODE>java.io.Serializable</CODE> interface.  This
057       * value was generated using the <CODE>serialver</CODE> command-line utility
058       * included with the Java SDK.
059       */
060      private static final long serialVersionUID = -3877941142853469687L;
061    
062    
063    
064      /**
065       * Creates a new instance of this uuidOrderingMatch matching rule.
066       */
067      public UUIDOrderingMatchingRule()
068      {
069        super();
070      }
071    
072    
073    
074      /**
075       * {@inheritDoc}
076       */
077      public void initializeMatchingRule(OrderingMatchingRuleCfg configuration)
078             throws ConfigException, InitializationException
079      {
080        // No initialization is required.
081      }
082    
083    
084    
085      /**
086       * Retrieves the common name for this matching rule.
087       *
088       * @return  The common name for this matching rule, or <CODE>null</CODE> if
089       * it does not have a name.
090       */
091      public String getName()
092      {
093        return OMR_UUID_NAME;
094      }
095    
096    
097    
098      /**
099       * Retrieves the OID for this matching rule.
100       *
101       * @return  The OID for this matching rule.
102       */
103      public String getOID()
104      {
105        return OMR_UUID_OID;
106      }
107    
108    
109    
110      /**
111       * Retrieves the description for this matching rule.
112       *
113       * @return  The description for this matching rule, or <CODE>null</CODE> if
114       *          there is none.
115       */
116      public String getDescription()
117      {
118        // There is no standard description for this matching rule.
119        return null;
120      }
121    
122    
123    
124      /**
125       * Retrieves the OID of the syntax with which this matching rule is
126       * associated.
127       *
128       * @return  The OID of the syntax with which this matching rule is associated.
129       */
130      public String getSyntaxOID()
131      {
132        return SYNTAX_UUID_OID;
133      }
134    
135    
136    
137      /**
138       * Retrieves the normalized form of the provided value, which is best suited
139       * for efficiently performing matching operations on that value.
140       *
141       * @param  value  The value to be normalized.
142       *
143       * @return  The normalized version of the provided value.
144       *
145       * @throws  DirectoryException  If the provided value is invalid according to
146       *                              the associated attribute syntax.
147       */
148      public ByteString normalizeValue(ByteString value)
149             throws DirectoryException
150      {
151        byte[] valueBytes = value.value();
152        if (valueBytes.length != 36)
153        {
154          Message message = WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH.get(
155                  value.stringValue(), valueBytes.length);
156          switch (DirectoryServer.getSyntaxEnforcementPolicy())
157          {
158            case REJECT:
159              throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
160                                           message);
161            case WARN:
162              ErrorLogger.logError(message);
163              return new ASN1OctetString(valueBytes);
164            default:
165              return new ASN1OctetString(valueBytes);
166          }
167        }
168    
169        byte[] normBytes = new byte[36];
170        System.arraycopy(valueBytes, 0, normBytes, 0, 36);
171        for (int i=0; i < 36; i++)
172        {
173          // The 9th, 14th, 19th, and 24th characters must be dashes.  All others
174          // must be hex.  Convert all uppercase hex characters to lowercase.
175          switch (i)
176          {
177            case 8:
178            case 13:
179            case 18:
180            case 23:
181              if (normBytes[i] != '-')
182              {
183                Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH.get(
184                        value.stringValue(), i, String.valueOf(normBytes[i]));
185                switch (DirectoryServer.getSyntaxEnforcementPolicy())
186                {
187                  case REJECT:
188                    throw new DirectoryException(
189                                   ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
190                  case WARN:
191                    ErrorLogger.logError(message);
192                    return new ASN1OctetString(valueBytes);
193                  default:
194                    return new ASN1OctetString(valueBytes);
195                }
196              }
197              break;
198            default:
199              switch (normBytes[i])
200              {
201                case '0':
202                case '1':
203                case '2':
204                case '3':
205                case '4':
206                case '5':
207                case '6':
208                case '7':
209                case '8':
210                case '9':
211                case 'a':
212                case 'b':
213                case 'c':
214                case 'd':
215                case 'e':
216                case 'f':
217                  // These are all fine.
218                  break;
219                case 'A':
220                  normBytes[i] = 'a';
221                  break;
222                case 'B':
223                  normBytes[i] = 'b';
224                  break;
225                case 'C':
226                  normBytes[i] = 'c';
227                  break;
228                case 'D':
229                  normBytes[i] = 'd';
230                  break;
231                case 'E':
232                  normBytes[i] = 'e';
233                  break;
234                case 'F':
235                  normBytes[i] = 'f';
236                  break;
237                default:
238                  Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX.get(
239                          value.stringValue(), i, String.valueOf(normBytes[i]));
240                  switch (DirectoryServer.getSyntaxEnforcementPolicy())
241                  {
242                    case REJECT:
243                      throw new DirectoryException(
244                                     ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
245                    case WARN:
246                      ErrorLogger.logError(message);
247                      return new ASN1OctetString(valueBytes);
248                    default:
249                      return new ASN1OctetString(valueBytes);
250                  }
251              }
252          }
253        }
254    
255        return new ASN1OctetString(normBytes);
256      }
257    
258    
259    
260      /**
261       * Compares the first value to the second and returns a value that indicates
262       * their relative order.
263       *
264       * @param  value1  The normalized form of the first value to compare.
265       * @param  value2  The normalized form of the second value to compare.
266       *
267       * @return  A negative integer if <CODE>value1</CODE> should come before
268       *          <CODE>value2</CODE> in ascending order, a positive integer if
269       *          <CODE>value1</CODE> should come after <CODE>value2</CODE> in
270       *          ascending order, or zero if there is no difference between the
271       *          values with regard to ordering.
272       */
273      public int compareValues(ByteString value1, ByteString value2)
274      {
275        return compare(value1.value(), value2.value());
276      }
277    
278    
279    
280      /**
281       * Compares the contents of the provided byte arrays to determine their
282       * relative order.
283       *
284       * @param  b1  The first byte array to use in the comparison.
285       * @param  b2  The second byte array to use in the comparison.
286       *
287       * @return  A negative integer if <CODE>b1</CODE> should come before
288       *          <CODE>b2</CODE> in ascending order, a positive integer if
289       *          <CODE>b1</CODE> should come after <CODE>b2</CODE> in ascending
290       *          order, or zero if there is no difference between the values with
291       *          regard to ordering.
292       */
293      public int compare(byte[] b1, byte[] b2)
294      {
295        int minLength = Math.min(b1.length, b2.length);
296    
297        for (int i=0; i < minLength; i++)
298        {
299          if (b1[i] == b2[i])
300          {
301            continue;
302          }
303          else if (b1[i] < b2[i])
304          {
305            return -1;
306          }
307          else if (b1[i] > b2[i])
308          {
309            return 1;
310          }
311        }
312    
313        if (b1.length == b2.length)
314        {
315          return 0;
316        }
317        else if (b1.length < b2.length)
318        {
319          return -1;
320        }
321        else
322        {
323          return 1;
324        }
325      }
326    }
327