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 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.types;
028    
029    
030    
031    import org.opends.server.api.OrderingMatchingRule;
032    
033    import static org.opends.server.loggers.debug.DebugLogger.*;
034    import org.opends.server.loggers.debug.DebugTracer;
035    
036    
037    
038    /**
039     * This class defines a data structure that may be used as a sort key.
040     * It includes an attribute type and a boolean value that indicates
041     * whether the sort should be ascending or descending.  It may also
042     * contain a specific ordering matching rule that should be used for
043     * the sorting process, although if none is provided it will use the
044     * default ordering matching rule for the attribute type.
045     */
046    @org.opends.server.types.PublicAPI(
047         stability=org.opends.server.types.StabilityLevel.VOLATILE,
048         mayInstantiate=true,
049         mayExtend=false,
050         mayInvoke=true)
051    public final class SortKey
052    {
053      /**
054       * The tracer object for the debug logger.
055       */
056      private static final DebugTracer TRACER = getTracer();
057    
058      // The attribute type for this sort key.
059      private AttributeType attributeType;
060    
061      // The indication of whether the sort should be ascending.
062      private boolean ascending;
063    
064      // The ordering matching rule to use with this sort key.
065      private OrderingMatchingRule orderingRule;
066    
067    
068    
069      /**
070       * Creates a new sort key with the provided information.
071       *
072       * @param  attributeType  The attribute type for this sort key.
073       * @param  ascending      Indicates whether the sort should be in
074       *                        ascending order rather than descending.
075       */
076      public SortKey(AttributeType attributeType, boolean ascending)
077      {
078        this.attributeType = attributeType;
079        this.ascending     = ascending;
080    
081        orderingRule = null;
082      }
083    
084    
085    
086      /**
087       * Creates a new sort key with the provided information.
088       *
089       * @param  attributeType  The attribute type for this sort key.
090       * @param  ascending      Indicates whether the sort should be in
091       *                        ascending order rather than descending.
092       * @param  orderingRule   The ordering matching rule to use with
093       *                        this sort key.
094       */
095      public SortKey(AttributeType attributeType, boolean ascending,
096                     OrderingMatchingRule orderingRule)
097      {
098        this.attributeType = attributeType;
099        this.ascending     = ascending;
100        this.orderingRule  = orderingRule;
101      }
102    
103    
104    
105      /**
106       * Retrieves the attribute type for this sort key.
107       *
108       * @return  The attribute type for this sort key.
109       */
110      public AttributeType getAttributeType()
111      {
112        return attributeType;
113      }
114    
115    
116    
117      /**
118       * Indicates whether the specified attribute should be sorted in
119       * ascending order.
120       *
121       * @return  {@code true} if the attribute should be sorted in
122       *          ascending order, or {@code false} if it should be sorted
123       *          in descending order.
124       */
125      public boolean ascending()
126      {
127        return ascending;
128      }
129    
130    
131    
132      /**
133       * Retrieves the ordering matching rule to use with this sort key.
134       *
135       * @return  The ordering matching rule to use with this sort key.
136       */
137      public OrderingMatchingRule getOrderingRule()
138      {
139        return orderingRule;
140      }
141    
142    
143    
144      /**
145       * Compares the provided values using this sort key.
146       *
147       * @param  value1  The first value to be compared.
148       * @param  value2  The second value to be compared.
149       *
150       * @return  A negative value if the first value should come before
151       *          the second in a sorted list, a positive value if the
152       *          first value should come after the second in a sorted
153       *          list, or zero if there is no relative difference between
154       *          the values.
155       */
156      public int compareValues(AttributeValue value1,
157                               AttributeValue value2)
158      {
159        // A null value will always come after a non-null value.
160        if (value1 == null)
161        {
162          if (value2 == null)
163          {
164            return 0;
165          }
166          else
167          {
168            return 1;
169          }
170        }
171        else if (value2 == null)
172        {
173          return -1;
174        }
175    
176    
177        // Use the ordering matching rule if one is provided.  Otherwise,
178        // fall back on the default ordering rule for the attribute type.
179        if (orderingRule == null)
180        {
181          try
182          {
183            OrderingMatchingRule rule =
184                 attributeType.getOrderingMatchingRule();
185            if (rule == null)
186            {
187              return 0;
188            }
189    
190            if (ascending)
191            {
192              return rule.compareValues(value1.getNormalizedValue(),
193                                        value2.getNormalizedValue());
194            }
195            else
196            {
197              return rule.compareValues(value2.getNormalizedValue(),
198                                        value1.getNormalizedValue());
199            }
200          }
201          catch (Exception e)
202          {
203            if (debugEnabled())
204            {
205              TRACER.debugCaught(DebugLogLevel.ERROR, e);
206            }
207    
208            return 0;
209          }
210        }
211        else
212        {
213          try
214          {
215            if (ascending)
216            {
217              return orderingRule.compareValues(
218                          orderingRule.normalizeValue(value1.getValue()),
219                          orderingRule.normalizeValue(value2.getValue()));
220            }
221            else
222            {
223              return orderingRule.compareValues(
224                          orderingRule.normalizeValue(value2.getValue()),
225                          orderingRule.normalizeValue(value1.getValue()));
226            }
227          }
228          catch (Exception e)
229          {
230            if (debugEnabled())
231            {
232              TRACER.debugCaught(DebugLogLevel.ERROR, e);
233            }
234    
235            return 0;
236          }
237        }
238      }
239    
240    
241    
242      /**
243       * Retrieves a string representation of this sort key.
244       *
245       * @return  A string representation of this sort key.
246       */
247      public String toString()
248      {
249        StringBuilder buffer = new StringBuilder();
250        toString(buffer);
251        return buffer.toString();
252      }
253    
254    
255    
256      /**
257       * Appends a string representation of this sort key to the
258       * provided buffer.
259       *
260       * @param  buffer  The buffer to which the information should be
261       *                 appended.
262       */
263      public void toString(StringBuilder buffer)
264      {
265        buffer.append("SortKey(");
266        if (ascending)
267        {
268          buffer.append("+");
269        }
270        else
271        {
272          buffer.append("-");
273        }
274        buffer.append(attributeType.getNameOrOID());
275    
276        if (orderingRule != null)
277        {
278          buffer.append(":");
279          buffer.append(orderingRule.getNameOrOID());
280        }
281    
282        buffer.append(")");
283      }
284    
285      /**
286       * Retrieves the hash code for this sort key.
287       *
288       * @return  The hash code for this sort key.
289       */
290      public int hashCode()
291      {
292        int hashCode = 0;
293    
294        if(ascending)
295        {
296          hashCode += 1;
297        }
298    
299        hashCode += attributeType.hashCode();
300    
301        if(orderingRule != null)
302        {
303          hashCode += orderingRule.hashCode();
304        }
305    
306        return hashCode;
307      }
308    
309      /**
310       * Indicates whether this sort key is equal to the provided
311       * object.
312       *
313       * @param  o  The object for which to make the determination.
314       *
315       * @return  <CODE>true</CODE> if the provide object is equal to this
316       *          sort key, or <CODE>false</CODE> if it is not.
317       */
318      public boolean equals(Object o)
319      {
320        if(o == null)
321        {
322          return false;
323        }
324    
325        if (o == this)
326        {
327          return true;
328        }
329    
330        if (! (o instanceof SortKey))
331        {
332          return false;
333        }
334    
335        SortKey s = (SortKey) o;
336    
337        if(ascending != s.ascending)
338        {
339          return false;
340        }
341    
342        if(!attributeType.equals(s.attributeType))
343        {
344          return false;
345        }
346    
347        if(orderingRule != null)
348        {
349          if(s.orderingRule != null)
350          {
351            if(!orderingRule.equals(s.orderingRule))
352            {
353              return false;
354            }
355          }
356          else if(!orderingRule.equals(
357              s.attributeType.getOrderingMatchingRule()))
358          {
359            return false;
360          }
361        }
362        else if(s.orderingRule != null)
363        {
364          if(!attributeType.getOrderingMatchingRule().equals(
365              s.orderingRule))
366          {
367            return false;
368          }
369        }
370    
371        return true;
372      }
373    }
374