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 ForgeRock AS 026 */ 027package org.opends.server.backends.jeb; 028 029import java.util.Collection; 030 031import org.forgerock.i18n.LocalizableMessageBuilder; 032 033import static org.opends.server.backends.jeb.IndexFilter.*; 034 035/** 036 * This class represents a JE Backend Query. 037 */ 038@org.opends.server.types.PublicAPI( 039 stability = org.opends.server.types.StabilityLevel.VOLATILE, 040 mayInstantiate = false, 041 mayExtend = true, 042 mayInvoke = false) 043public abstract class IndexQuery 044{ 045 /** 046 * Evaluates the index query and returns the EntryIDSet. 047 * 048 * @param debugMessage If not null, diagnostic message will be written 049 * which will help to determine why the returned 050 * EntryIDSet is not defined. 051 * @return The EntryIDSet as a result of evaluation of this query. 052 */ 053 public abstract EntryIDSet evaluate(LocalizableMessageBuilder debugMessage); 054 055 056 057 /** 058 * Creates an IntersectionIndexQuery object from a collection of 059 * IndexQuery objects. 060 * 061 * @param subIndexQueries 062 * A collection of IndexQuery objects. 063 * @return An IntersectionIndexQuery object. 064 */ 065 public static IndexQuery createIntersectionIndexQuery( 066 Collection<IndexQuery> subIndexQueries) 067 { 068 return new IntersectionIndexQuery(subIndexQueries); 069 } 070 071 072 073 /** 074 * Creates a union IndexQuery object from a collection of IndexQuery 075 * objects. 076 * 077 * @param subIndexQueries 078 * Collection of IndexQuery objects. 079 * @return A UnionIndexQuery object. 080 */ 081 public static IndexQuery createUnionIndexQuery( 082 Collection<IndexQuery> subIndexQueries) 083 { 084 return new UnionIndexQuery(subIndexQueries); 085 } 086 087 088 089 /** 090 * Creates an empty IndexQuery object. 091 * 092 * @return A NullIndexQuery object. 093 */ 094 public static IndexQuery createNullIndexQuery() 095 { 096 return new NullIndexQuery(); 097 } 098 099 100 101 /** 102 * This class creates a Null IndexQuery. It is used when there is no 103 * record in the index. It may also be used when the index contains 104 * all the records but an empty EntryIDSet should be returned as part 105 * of the optimization. 106 */ 107 private static final class NullIndexQuery extends IndexQuery 108 { 109 /** {@inheritDoc} */ 110 @Override 111 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 112 { 113 return new EntryIDSet(); 114 } 115 } 116 117 /** 118 * This class creates an intersection IndexQuery from a collection of 119 * IndexQuery objects. 120 */ 121 private static final class IntersectionIndexQuery extends IndexQuery 122 { 123 /** 124 * Collection of IndexQuery objects. 125 */ 126 private final Collection<IndexQuery> subIndexQueries; 127 128 129 130 /** 131 * Creates an instance of IntersectionIndexQuery. 132 * 133 * @param subIndexQueries 134 * Collection of IndexQuery objects. 135 */ 136 private IntersectionIndexQuery(Collection<IndexQuery> subIndexQueries) 137 { 138 this.subIndexQueries = subIndexQueries; 139 } 140 141 /** {@inheritDoc} */ 142 @Override 143 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 144 { 145 EntryIDSet entryIDs = null; 146 for (IndexQuery query : subIndexQueries) 147 { 148 if (entryIDs == null) 149 { 150 entryIDs = query.evaluate(debugMessage); 151 } 152 else 153 { 154 entryIDs.retainAll(query.evaluate(debugMessage)); 155 } 156 if (entryIDs.isDefined() 157 && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD) 158 { 159 break; 160 } 161 } 162 return entryIDs; 163 } 164 } 165 166 /** 167 * This class creates a union of IndexQuery objects. 168 */ 169 private static final class UnionIndexQuery extends IndexQuery 170 { 171 /** 172 * Collection containing IndexQuery objects. 173 */ 174 private final Collection<IndexQuery> subIndexQueries; 175 176 177 178 /** 179 * Creates an instance of UnionIndexQuery. 180 * 181 * @param subIndexQueries 182 * The Collection of IndexQuery objects. 183 */ 184 private UnionIndexQuery(Collection<IndexQuery> subIndexQueries) 185 { 186 this.subIndexQueries = subIndexQueries; 187 } 188 189 /** {@inheritDoc} */ 190 @Override 191 public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) 192 { 193 EntryIDSet entryIDs = null; 194 for (IndexQuery query : subIndexQueries) 195 { 196 if (entryIDs == null) 197 { 198 entryIDs = query.evaluate(debugMessage); 199 } 200 else 201 { 202 entryIDs.addAll(query.evaluate(debugMessage)); 203 } 204 if (entryIDs.isDefined() 205 && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD) 206 { 207 break; 208 } 209 } 210 return entryIDs; 211 } 212 } 213}