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 2009-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.backends.jeb; 028 029import java.util.HashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033 034import org.forgerock.i18n.slf4j.LocalizedLogger; 035import org.forgerock.opendj.ldap.ByteString; 036import org.forgerock.opendj.ldap.DecodeException; 037import org.forgerock.opendj.ldap.schema.Schema; 038import org.opends.server.types.Attribute; 039import org.opends.server.types.AttributeType; 040import org.opends.server.types.Entry; 041import org.opends.server.types.Modification; 042 043/** 044 * This class implements an attribute indexer for matching rules in JE Backend. 045 */ 046public final class AttributeIndexer extends Indexer 047{ 048 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 049 050 /** The attribute type for which this instance will generate index keys. */ 051 private final AttributeType attributeType; 052 053 /** 054 * The indexer which will generate the keys 055 * for the associated extensible matching rule. 056 */ 057 private final org.forgerock.opendj.ldap.spi.Indexer indexer; 058 059 /** 060 * Creates a new extensible indexer for JE backend. 061 * 062 * @param attributeType The attribute type for which an indexer is 063 * required. 064 * @param extensibleIndexer The extensible indexer to be used. 065 */ 066 public AttributeIndexer(AttributeType attributeType, org.forgerock.opendj.ldap.spi.Indexer extensibleIndexer) 067 { 068 this.attributeType = attributeType; 069 this.indexer = extensibleIndexer; 070 } 071 072 /** {@inheritDoc} */ 073 @Override 074 public String toString() 075 { 076 return attributeType.getNameOrOID() + "." + indexer.getIndexID(); 077 } 078 079 /** {@inheritDoc} */ 080 @Override 081 public void indexEntry(Entry entry, Set<ByteString> keys) 082 { 083 final List<Attribute> attrList = entry.getAttribute(attributeType); 084 if (attrList != null) 085 { 086 indexAttribute(attrList, keys); 087 } 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public void modifyEntry(Entry oldEntry, Entry newEntry, 093 List<Modification> mods, Map<ByteString, Boolean> modifiedKeys) 094 { 095 List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true); 096 List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true); 097 098 indexAttribute(oldAttributes, modifiedKeys, false); 099 indexAttribute(newAttributes, modifiedKeys, true); 100 } 101 102 103 104 /** 105 * Generates the set of extensible index keys for an attribute. 106 * @param attrList The attribute for which substring keys are required. 107 * @param keys The set into which the generated keys will be inserted. 108 */ 109 private void indexAttribute(List<Attribute> attrList, Set<ByteString> keys) 110 { 111 if (attrList == null) 112 { 113 return; 114 } 115 116 for (Attribute attr : attrList) 117 { 118 if (!attr.isVirtual()) 119 { 120 for (ByteString value : attr) 121 { 122 try 123 { 124 indexer.createKeys(Schema.getDefaultSchema(), value, keys); 125 } 126 catch (DecodeException e) 127 { 128 logger.traceException(e); 129 } 130 } 131 } 132 } 133 } 134 135 /** 136 * Generates the set of index keys for an attribute. 137 * @param attrList The attribute to be indexed. 138 * @param modifiedKeys The map into which the modified 139 * keys will be inserted. 140 * @param insert <code>true</code> if generated keys should 141 * be inserted or <code>false</code> otherwise. 142 */ 143 private void indexAttribute(List<Attribute> attrList, Map<ByteString, Boolean> modifiedKeys, Boolean insert) 144 { 145 if (attrList == null) 146 { 147 return; 148 } 149 150 final Set<ByteString> keys = new HashSet<>(); 151 indexAttribute(attrList, keys); 152 computeModifiedKeys(modifiedKeys, insert, keys); 153 } 154 155 /** 156 * Computes a map of index keys and a boolean flag indicating whether the 157 * corresponding key will be inserted or deleted. 158 * 159 * @param modifiedKeys 160 * A map containing the keys and a boolean. Keys corresponding to the 161 * boolean value <code>true</code> should be inserted and 162 * <code>false</code> should be deleted. 163 * @param insert 164 * <code>true</code> if generated keys should be inserted or 165 * <code>false</code> otherwise. 166 * @param keys 167 * The index keys to map. 168 */ 169 private static void computeModifiedKeys(Map<ByteString, Boolean> modifiedKeys, 170 Boolean insert, Set<ByteString> keys) 171 { 172 for (ByteString key : keys) 173 { 174 Boolean cInsert = modifiedKeys.get(key); 175 if (cInsert == null) 176 { 177 modifiedKeys.put(key, insert); 178 } 179 else if (!cInsert.equals(insert)) 180 { 181 modifiedKeys.remove(key); 182 } 183 } 184 } 185}