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 }