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.Collection; 030import java.util.Map; 031 032import org.forgerock.i18n.LocalizableMessageBuilder; 033import org.forgerock.opendj.ldap.ByteSequence; 034import org.forgerock.opendj.ldap.spi.IndexQueryFactory; 035import org.forgerock.opendj.ldap.spi.IndexingOptions; 036import org.opends.server.types.AttributeType; 037 038import com.sleepycat.je.DatabaseEntry; 039import com.sleepycat.je.LockMode; 040 041import static org.opends.messages.BackendMessages.*; 042 043/** 044 * This class is an implementation of IndexQueryFactory which creates 045 * IndexQuery objects as part of the query of the JEB index. 046 */ 047public final class IndexQueryFactoryImpl implements 048 IndexQueryFactory<IndexQuery> 049{ 050 051 private static final String PRESENCE_INDEX_KEY = "presence"; 052 053 /** 054 * The Map containing the string type identifier and the corresponding index. 055 */ 056 private final Map<String, Index> indexMap; 057 private final IndexingOptions indexingOptions; 058 private final AttributeType attribute; 059 060 /** 061 * Creates a new IndexQueryFactoryImpl object. 062 * 063 * @param indexMap 064 * A map containing the index id and the corresponding index. 065 * @param indexingOptions 066 * The options to use for indexing 067 * @param attribute 068 * The Attribute type of this index, for error messages 069 */ 070 public IndexQueryFactoryImpl(Map<String, Index> indexMap, IndexingOptions indexingOptions, AttributeType attribute) 071 { 072 this.indexMap = indexMap; 073 this.indexingOptions = indexingOptions; 074 this.attribute = attribute; 075 } 076 077 078 079 /** {@inheritDoc} */ 080 @Override 081 public IndexQuery createExactMatchQuery(final String indexID, final ByteSequence value) 082 { 083 return new IndexQuery() 084 { 085 086 @Override 087 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 088 { 089 // Read the database and get Record for the key. 090 DatabaseEntry key = new DatabaseEntry(value.toByteArray()); 091 092 // Select the right index to be used. 093 Index index = indexMap.get(indexID); 094 if (index == null) 095 { 096 if(debugMessage != null) 097 { 098 debugMessage.append(INFO_INDEX_FILTER_INDEX_TYPE_DISABLED.get(indexID, attribute.getNameOrOID())); 099 } 100 return createMatchAllQuery().evaluate(debugMessage); 101 } 102 EntryIDSet entrySet = index.readKey(key, null, LockMode.DEFAULT); 103 if(debugMessage != null && !entrySet.isDefined()) 104 { 105 updateStatsUndefinedResults(debugMessage, index); 106 } 107 return entrySet; 108 } 109 }; 110 } 111 112 113 114 /** {@inheritDoc} */ 115 @Override 116 public IndexQuery createRangeMatchQuery(final String indexID, 117 final ByteSequence lowerBound, final ByteSequence upperBound, 118 final boolean includeLowerBound, final boolean includeUpperBound) 119 { 120 return new IndexQuery() 121 { 122 123 @Override 124 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 125 { 126 // Find the right index. 127 Index index = indexMap.get(indexID); 128 if (index == null) 129 { 130 if(debugMessage != null) 131 { 132 debugMessage.append(INFO_INDEX_FILTER_INDEX_TYPE_DISABLED.get(indexID, attribute.getNameOrOID())); 133 } 134 return createMatchAllQuery().evaluate(debugMessage); 135 } 136 EntryIDSet entrySet = index.readRange(lowerBound.toByteArray(), upperBound.toByteArray(), 137 includeLowerBound, includeUpperBound); 138 if(debugMessage != null && !entrySet.isDefined()) 139 { 140 updateStatsUndefinedResults(debugMessage, index); 141 } 142 return entrySet; 143 } 144 }; 145 } 146 147 148 149 /** {@inheritDoc} */ 150 @Override 151 public IndexQuery createIntersectionQuery(Collection<IndexQuery> subqueries) 152 { 153 return IndexQuery.createIntersectionIndexQuery(subqueries); 154 } 155 156 157 158 /** {@inheritDoc} */ 159 @Override 160 public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries) 161 { 162 return IndexQuery.createUnionIndexQuery(subqueries); 163 } 164 165 166 167 /** 168 * {@inheritDoc} 169 * <p> 170 * It returns an empty EntryIDSet object when either all or no record 171 * sets are requested. 172 */ 173 @Override 174 public IndexQuery createMatchAllQuery() 175 { 176 return new IndexQuery() 177 { 178 @Override 179 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 180 { 181 final String indexID = PRESENCE_INDEX_KEY; 182 final Index index = indexMap.get(indexID); 183 if (index == null) 184 { 185 if(debugMessage != null) 186 { 187 debugMessage.append(INFO_INDEX_FILTER_INDEX_TYPE_DISABLED.get(indexID, attribute.getNameOrOID())); 188 } 189 return new EntryIDSet(); 190 } 191 192 EntryIDSet entrySet = index.readKey(JEBUtils.presenceKey, null, LockMode.DEFAULT); 193 if (debugMessage != null && !entrySet.isDefined()) 194 { 195 updateStatsUndefinedResults(debugMessage, index); 196 } 197 return entrySet; 198 } 199 }; 200 } 201 202 private static void updateStatsUndefinedResults(LocalizableMessageBuilder debugMessage, Index index) 203 { 204 if (!index.isTrusted()) 205 { 206 debugMessage.append(INFO_INDEX_FILTER_INDEX_NOT_TRUSTED.get(index.getName())); 207 } 208 else if (index.isRebuildRunning()) 209 { 210 debugMessage.append(INFO_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get(index.getName())); 211 } 212 else 213 { 214 debugMessage.append(INFO_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get(index.getName())); 215 } 216 } 217 218 /** {@inheritDoc} */ 219 @Override 220 public IndexingOptions getIndexingOptions() 221 { 222 return indexingOptions; 223 } 224}