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