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.backends.jeb;
028
029
030
031 import java.util.List;
032
033 import org.opends.server.types.Attribute;
034 import org.opends.server.types.AttributeType;
035 import org.opends.server.types.AttributeValue;
036 import org.opends.server.types.Entry;
037 import org.opends.server.types.SortKey;
038 import org.opends.server.types.SortOrder;
039
040
041 /**
042 * This class defines a data structure that holds a set of attribute values that
043 * are associated with a sort order for a given entry. Any or all of the
044 * attribute values may be {@code null} if the entry does not include any values
045 * for the attribute type targeted by the corresponding sort key.
046 * <BR><BR>
047 * This class implements the {@code Comparable} interface and may therefore be
048 * used to order the elements in components like {@code TreeMap} and
049 * {@code TreeSet}.
050 */
051 public class SortValues
052 implements Comparable<SortValues>
053 {
054 // The set of sort keys in this sort order.
055 private AttributeValue[] values;
056
057 // The entry ID for the entry associated with this sort values.
058 private EntryID entryID;
059
060 // The sort order for this set of sort values.
061 private SortOrder sortOrder;
062
063
064
065 /**
066 * Creates a new sort values object with the provided information.
067 *
068 * @param entryID The entry ID for the entry associated with this set of
069 * values.
070 * @param values The attribute values for this sort values.
071 * @param sortOrder The sort order to use to obtain the necessary values.
072 */
073 public SortValues(EntryID entryID, AttributeValue[] values,
074 SortOrder sortOrder)
075 {
076 this.entryID = entryID;
077 this.sortOrder = sortOrder;
078 this.values = values;
079 }
080
081 /**
082 * Creates a new sort values object with the provided information.
083 *
084 * @param entryID The entry ID for the entry associated with this set of
085 * values.
086 * @param entry The entry containing the values to extract and use when
087 * sorting.
088 * @param sortOrder The sort order to use to obtain the necessary values.
089 */
090 public SortValues(EntryID entryID, Entry entry, SortOrder sortOrder)
091 {
092 this.entryID = entryID;
093 this.sortOrder = sortOrder;
094
095 SortKey[] sortKeys = sortOrder.getSortKeys();
096 values = new AttributeValue[sortKeys.length];
097 for (int i=0; i < sortKeys.length; i++)
098 {
099 SortKey sortKey = sortKeys[i];
100 AttributeType attrType = sortKey.getAttributeType();
101 List<Attribute> attrList = entry.getAttribute(attrType);
102 if (attrList != null)
103 {
104 AttributeValue sortValue = null;
105
106 // There may be multiple versions of this attribute in the target entry
107 // (e.g., with different sets of options), and it may also be a
108 // multivalued attribute. In that case, we need to find the value that
109 // is the best match for the corresponding sort key (i.e., for sorting
110 // in ascending order, we want to find the lowest value; for sorting in
111 // descending order, we want to find the highest value). This is
112 // handled by the SortKey.compareValues method.
113 for (Attribute a : attrList)
114 {
115 for (AttributeValue v : a.getValues())
116 {
117 if (sortValue == null)
118 {
119 sortValue = v;
120 }
121 else if (sortKey.compareValues(v, sortValue) < 0)
122 {
123 sortValue = v;
124 }
125 }
126 }
127
128 values[i] = sortValue;
129 }
130 }
131 }
132
133
134
135 /**
136 * Compares this set of sort values with the provided set of values to
137 * determine their relative order in a sorted list.
138 *
139 * @param sortValues The set of values to compare against this sort values.
140 * It must also have the same sort order as this set of
141 * values.
142 *
143 * @return A negative value if this sort values object should come before the
144 * provided values in a sorted list, a positive value if this sort
145 * values object should come after the provided values in a sorted
146 * list, or zero if there is no significant difference in their
147 * relative order.
148 */
149 public int compareTo(SortValues sortValues)
150 {
151 SortKey[] sortKeys = sortOrder.getSortKeys();
152
153 for (int i=0; i < values.length; i++)
154 {
155 int compareValue = sortKeys[i].compareValues(values[i],
156 sortValues.values[i]);
157 if (compareValue != 0)
158 {
159 return compareValue;
160 }
161 }
162
163 // If we've gotten here, then we can't tell a difference between the sets of
164 // sort values, so sort based on entry ID.
165 long idDifference = (entryID.longValue() - sortValues.entryID.longValue());
166 if (idDifference < 0)
167 {
168 return -1;
169 }
170 else if (idDifference > 0)
171 {
172 return 1;
173 }
174 else
175 {
176 return 0;
177 }
178 }
179
180
181
182 /**
183 * Compares the first element in this set of sort values with the provided
184 * assertion value to determine whether the assertion value is greater than or
185 * equal to the initial sort value. This is used during VLV processing to
186 * find the offset by assertion value.
187 *
188 * @param assertionValue The assertion value to compare against the first
189 * sort value.
190 *
191 * @return A negative value if the provided assertion value should come
192 * before the first sort value, zero if the provided assertion value
193 * is equal to the first sort value, or a positive value if the
194 * provided assertion value should come after the first sort value.
195 */
196 public int compareTo(AttributeValue assertionValue)
197 {
198 SortKey sortKey = sortOrder.getSortKeys()[0];
199 return sortKey.compareValues(values[0], assertionValue);
200 }
201
202
203
204 /**
205 * Retrieves a string representation of this sort values object.
206 *
207 * @return A string representation of this sort values object.
208 */
209 public String toString()
210 {
211 StringBuilder buffer = new StringBuilder();
212 toString(buffer);
213 return buffer.toString();
214 }
215
216
217
218 /**
219 * Appends a string representation of this sort values object to the provided
220 * buffer.
221 *
222 * @param buffer The buffer to which the information should be appended.
223 */
224 public void toString(StringBuilder buffer)
225 {
226 buffer.append("SortValues(");
227
228 SortKey[] sortKeys = sortOrder.getSortKeys();
229 for (int i=0; i < sortKeys.length; i++)
230 {
231 if (i > 0)
232 {
233 buffer.append(",");
234 }
235
236 if (sortKeys[i].ascending())
237 {
238 buffer.append("+");
239 }
240 else
241 {
242 buffer.append("-");
243 }
244
245 buffer.append(sortKeys[i].getAttributeType().getNameOrOID());
246 buffer.append("=");
247 if (values[i] == null)
248 {
249 buffer.append("null");
250 }
251 else
252 {
253 buffer.append(values[i].getStringValue());
254 }
255 }
256
257 buffer.append(", id=");
258 buffer.append(entryID.toString());
259 buffer.append(")");
260 }
261
262 /**
263 * Retrieve the attribute values in this sort values.
264 *
265 * @return The array of attribute values for this sort values.
266 */
267 public AttributeValue[] getValues()
268 {
269 return values;
270 }
271
272 /**
273 * Retrieve the entry ID in this sort values.
274 *
275 * @return The entry ID for this sort values.
276 */
277 public long getEntryID()
278 {
279 return entryID.longValue();
280 }
281 }
282
283