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