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