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