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}