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 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.backends.jeb;
028    
029    import static org.opends.server.loggers.debug.DebugLogger.*;
030    import org.opends.server.loggers.debug.DebugTracer;
031    import org.opends.server.types.DebugLogLevel;
032    
033    import org.opends.server.api.OrderingMatchingRule;
034    import org.opends.server.types.Attribute;
035    import org.opends.server.types.AttributeType;
036    import org.opends.server.types.AttributeValue;
037    import org.opends.server.types.DirectoryException;
038    import org.opends.server.types.Entry;
039    import org.opends.server.types.Modification;
040    
041    import java.util.*;
042    
043    /**
044     * An implementation of an Indexer for attribute ordering.
045     */
046    public class OrderingIndexer extends Indexer
047    {
048      /**
049       * The tracer object for the debug logger.
050       */
051      private static final DebugTracer TRACER = getTracer();
052    
053    
054    
055      /**
056       * The attribute type for which this instance will
057       * generate index keys.
058       */
059      private AttributeType attributeType;
060    
061      /**
062       * The attribute type ordering matching rule which is also the
063       * comparator for the index keys generated by this class.
064       */
065      private OrderingMatchingRule orderingRule;
066    
067    
068      /**
069       * Create a new attribute ordering indexer for the given index configuration.
070       * @param attributeType The attribute type for which an indexer is
071       * required.
072       */
073      public OrderingIndexer(AttributeType attributeType)
074      {
075        this.attributeType = attributeType;
076        this.orderingRule = attributeType.getOrderingMatchingRule();
077      }
078    
079      /**
080       * Get a string representation of this object.  The returned value is
081       * used to name an index created using this object.
082       * @return A string representation of this object.
083       */
084      public String toString()
085      {
086        return attributeType.getNameOrOID() + ".ordering";
087      }
088    
089      /**
090       * Get the comparator that must be used to compare index keys
091       * generated by this class.
092       *
093       * @return A byte array comparator.
094       */
095      public Comparator<byte[]> getComparator()
096      {
097        return orderingRule;
098      }
099    
100      /**
101       * Generate the set of index keys for an entry.
102       *
103       * @param entry The entry.
104       * @param keys The set into which the generated keys will be inserted.
105       */
106      public void indexEntry(Entry entry, Set<byte[]> keys)
107      {
108        List<Attribute> attrList =
109             entry.getAttribute(attributeType);
110        if (attrList != null)
111        {
112          indexAttribute(attrList, keys);
113        }
114      }
115    
116      /**
117       * Generate the set of index keys to be added and the set of index keys
118       * to be deleted for an entry that has been replaced.
119       *
120       * @param oldEntry The original entry contents.
121       * @param newEntry The new entry contents.
122       * @param modifiedKeys The map into which the modified keys will be inserted.
123       */
124      public void replaceEntry(Entry oldEntry, Entry newEntry,
125                               Map<byte[], Boolean> modifiedKeys)
126      {
127        List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
128        List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
129    
130        indexAttribute(oldAttributes, modifiedKeys, false);
131        indexAttribute(newAttributes, modifiedKeys, true);
132      }
133    
134      /**
135       * Generate the set of index keys to be added and the set of index keys
136       * to be deleted for an entry that was modified.
137       *
138       * @param oldEntry The original entry contents.
139       * @param newEntry The new entry contents.
140       * @param mods The set of modifications that were applied to the entry.
141       * @param modifiedKeys The map into which the modified keys will be inserted.
142       */
143      public void modifyEntry(Entry oldEntry, Entry newEntry,
144                              List<Modification> mods,
145                              Map<byte[], Boolean> modifiedKeys)
146      {
147        List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
148        List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
149    
150        indexAttribute(oldAttributes, modifiedKeys, false);
151        indexAttribute(newAttributes, modifiedKeys, true);
152      }
153    
154    
155      /**
156       * Generate the set of index keys for a set of attribute values.
157       * @param values The set of attribute values to be indexed.
158       * @param keys The set into which the keys will be inserted.
159       */
160      private void indexValues(Set<AttributeValue> values,
161                               Set<byte[]> keys)
162      {
163        if (values == null) return;
164    
165        for (AttributeValue value : values)
166        {
167          try
168          {
169            byte[] keyBytes =
170                 orderingRule.normalizeValue(value.getValue()).value();
171    
172            keys.add(keyBytes);
173          }
174          catch (DirectoryException e)
175          {
176            if (debugEnabled())
177            {
178              TRACER.debugCaught(DebugLogLevel.ERROR, e);
179            }
180          }
181        }
182      }
183    
184      /**
185       * Generate the set of index keys for an attribute.
186       * @param attrList The attribute to be indexed.
187       * @param keys The set into which the keys will be inserted.
188       */
189      private void indexAttribute(List<Attribute> attrList,
190                                  Set<byte[]> keys)
191      {
192        if (attrList == null) return;
193    
194        for (Attribute attr : attrList)
195        {
196          indexValues(attr.getValues(), keys);
197        }
198      }
199    
200    
201      /**
202       * Generate the set of index keys for an attribute.
203       * @param attrList The attribute to be indexed.
204       * @param modifiedKeys The map into which the modified
205       * keys will be inserted.
206       * @param insert <code>true</code> if generated keys should
207       * be inserted or <code>false</code> otherwise.
208       */
209      private void indexAttribute(List<Attribute> attrList,
210                                  Map<byte[], Boolean> modifiedKeys,
211                                  Boolean insert)
212      {
213        if (attrList == null) return;
214    
215        for (Attribute attr : attrList)
216        {
217          indexValues(attr.getValues(), modifiedKeys, insert);
218        }
219      }
220    
221      /**
222       * Generate the set of index keys for a set of attribute values.
223       * @param values The set of attribute values to be indexed.
224       * @param modifiedKeys The map into which the modified
225       *  keys will be inserted.
226       * @param insert <code>true</code> if generated keys should
227       * be inserted or <code>false</code> otherwise.
228       */
229      private void indexValues(Set<AttributeValue> values,
230                               Map<byte[], Boolean> modifiedKeys,
231                               Boolean insert)
232      {
233        if (values == null) return;
234    
235        for (AttributeValue value : values)
236        {
237          try
238          {
239            byte[] keyBytes =
240                 orderingRule.normalizeValue(value.getValue()).value();
241    
242            Boolean cInsert = modifiedKeys.get(keyBytes);
243            if(cInsert == null)
244            {
245              modifiedKeys.put(keyBytes, insert);
246            }
247            else if(!cInsert.equals(insert))
248            {
249              modifiedKeys.remove(keyBytes);
250            }
251          }
252          catch (DirectoryException e)
253          {
254            if (debugEnabled())
255            {
256              TRACER.debugCaught(DebugLogLevel.ERROR, e);
257            }
258          }
259        }
260      }
261    }