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