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 Sun Microsystems, Inc.
025 *      Portions Copyright 2013 ForgeRock AS
026 */
027package org.forgerock.opendj.ldap;
028
029import java.util.Arrays;
030import java.util.Collections;
031import java.util.List;
032
033/**
034 * A Search operation search scope as defined in RFC 4511 section 4.5.1.2 is
035 * used to specify the scope of a Search operation.
036 *
037 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.2">RFC 4511 -
038 *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
039 * @see <a
040 *      href="http://tools.ietf.org/html/draft-sermersheim-ldap-subordinate-scope">
041 *      draft-sermersheim-ldap-subordinate-scope - Subordinate Subtree Search
042 *      Scope for LDAP </a>
043 */
044public final class SearchScope {
045
046    /**
047     * Contains equivalent values for the SearchScope values.
048     * This allows easily using SearchScope values with switch statements.
049     */
050    public static enum Enum {
051        //@Checkstyle:off
052        /** @see SearchScope#BASE_OBJECT */
053        BASE_OBJECT,
054        /** @see SearchScope#SINGLE_LEVEL */
055        SINGLE_LEVEL,
056        /** @see SearchScope#WHOLE_SUBTREE */
057        WHOLE_SUBTREE,
058        /** @see SearchScope#SUBORDINATES */
059        SUBORDINATES,
060        /** Used for unknown search scopes. */
061        UNKNOWN;
062        //@Checkstyle:on
063    }
064
065    private static final SearchScope[] ELEMENTS = new SearchScope[4];
066
067    private static final List<SearchScope> IMMUTABLE_ELEMENTS = Collections.unmodifiableList(Arrays
068            .asList(ELEMENTS));
069
070    /**
071     * The scope is constrained to the search base entry.
072     */
073    public static final SearchScope BASE_OBJECT = register(0, "base", Enum.BASE_OBJECT);
074
075    /**
076     * The scope is constrained to the immediate subordinates of the search base
077     * entry.
078     */
079    public static final SearchScope SINGLE_LEVEL = register(1, "one", Enum.SINGLE_LEVEL);
080
081    /**
082     * The scope is constrained to the search base entry and to all its
083     * subordinates.
084     */
085    public static final SearchScope WHOLE_SUBTREE = register(2, "sub", Enum.WHOLE_SUBTREE);
086
087    /**
088     * The scope is constrained to all the subordinates of the search base
089     * entry, but does not include the search base entry itself (as wholeSubtree
090     * does).
091     */
092    public static final SearchScope SUBORDINATES = register(3, "subordinates", Enum.SUBORDINATES);
093
094    /**
095     * Returns the search scope having the specified integer value as defined in
096     * RFC 4511 section 4.5.1.2.
097     *
098     * @param intValue
099     *            The integer value of the search scope.
100     * @return The search scope, or {@code null} if there was no search scope
101     *         associated with {@code intValue}.
102     */
103    public static SearchScope valueOf(final int intValue) {
104        SearchScope result = null;
105        if (0 <= intValue && intValue < ELEMENTS.length) {
106            result = ELEMENTS[intValue];
107        }
108        if (result == null) {
109            result = new SearchScope(intValue, "unknown(" + intValue + ")", Enum.UNKNOWN);
110        }
111        return result;
112    }
113
114    /**
115     * Returns the search scope having the specified name as defined in RFC 4511
116     * section 4.5.1.2.
117     *
118     * @param name
119     *          the name of the search scope to return
120     * @return The search scope, or {@code null} if there was no search scope
121     *         associated with {@code name}.
122     * @throws NullPointerException
123     *           if name is null
124     */
125    public static SearchScope valueOf(String name) {
126        for (SearchScope searchScope : ELEMENTS) {
127            if (searchScope.name.equals(name)) {
128                return searchScope;
129            }
130        }
131        return null;
132    }
133
134    /**
135     * Returns an unmodifiable list containing the set of available search
136     * scopes indexed on their integer value as defined in RFC 4511 section
137     * 4.5.1.2.
138     *
139     * @return An unmodifiable list containing the set of available search
140     *         scopes.
141     */
142    public static List<SearchScope> values() {
143        return IMMUTABLE_ELEMENTS;
144    }
145
146    /**
147     * Creates and registers a new search scope with the application.
148     *
149     * @param intValue
150     *            The integer value of the search scope as defined in RFC 4511
151     *            section 4.5.1.2.
152     * @param name
153     *            The name of the search scope as defined in RFC 4516.
154     * @param searchScopeEnum
155     *            The enum equivalent for this search scope
156     * @return The new search scope.
157     */
158    private static SearchScope register(final int intValue, final String name, Enum searchScopeEnum) {
159        final SearchScope t = new SearchScope(intValue, name, searchScopeEnum);
160        ELEMENTS[intValue] = t;
161        return t;
162    }
163
164    private final int intValue;
165
166    private final String name;
167
168    private final Enum searchScopeEnum;
169
170    /** Prevent direct instantiation. */
171    private SearchScope(final int intValue, final String name, Enum searchScopeEnum) {
172        this.intValue = intValue;
173        this.name = name;
174        this.searchScopeEnum = searchScopeEnum;
175    }
176
177    /** {@inheritDoc} */
178    @Override
179    public boolean equals(final Object obj) {
180        if (this == obj) {
181            return true;
182        } else if (obj instanceof SearchScope) {
183            return this.intValue == ((SearchScope) obj).intValue;
184        } else {
185            return false;
186        }
187    }
188
189    /** {@inheritDoc} */
190    @Override
191    public int hashCode() {
192        return intValue;
193    }
194
195    /**
196     * Returns the integer value of this search scope as defined in RFC 4511
197     * section 4.5.1.2.
198     *
199     * @return The integer value of this search scope.
200     */
201    public int intValue() {
202        return intValue;
203    }
204
205    /**
206     * Returns the enum equivalent for this search scope.
207     *
208     * @return The enum equivalent for this search scope when a known mapping exists,
209     *         or {@link Enum#UNKNOWN} if this is an unknown search scope.
210     */
211    public Enum asEnum() {
212        return this.searchScopeEnum;
213    }
214
215    /**
216     * Returns the string representation of this search scope as defined in RFC
217     * 4516.
218     *
219     * @return The string representation of this search scope.
220     */
221    @Override
222    public String toString() {
223        return name;
224    }
225}