001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.forgerock.opendj.ldap;
018
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.List;
022
023/**
024 * A Search operation search scope as defined in RFC 4511 section 4.5.1.2 is
025 * used to specify the scope of a Search operation.
026 *
027 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.2">RFC 4511 -
028 *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
029 * @see <a
030 *      href="http://tools.ietf.org/html/draft-sermersheim-ldap-subordinate-scope">
031 *      draft-sermersheim-ldap-subordinate-scope - Subordinate Subtree Search
032 *      Scope for LDAP </a>
033 */
034public final class SearchScope {
035    /**
036     * Contains equivalent values for the SearchScope values.
037     * This allows easily using SearchScope values with switch statements.
038     */
039    public static enum Enum {
040        //@Checkstyle:off
041        /** @see SearchScope#BASE_OBJECT */
042        BASE_OBJECT,
043        /** @see SearchScope#SINGLE_LEVEL */
044        SINGLE_LEVEL,
045        /** @see SearchScope#WHOLE_SUBTREE */
046        WHOLE_SUBTREE,
047        /** @see SearchScope#SUBORDINATES */
048        SUBORDINATES,
049        /** Used for unknown search scopes. */
050        UNKNOWN;
051        //@Checkstyle:on
052    }
053
054    private static final SearchScope[] ELEMENTS = new SearchScope[4];
055
056    private static final List<SearchScope> IMMUTABLE_ELEMENTS = Collections.unmodifiableList(Arrays
057            .asList(ELEMENTS));
058
059    /** The scope is constrained to the search base entry. */
060    public static final SearchScope BASE_OBJECT = register(0, "base", Enum.BASE_OBJECT);
061
062    /** The scope is constrained to the immediate subordinates of the search base entry. */
063    public static final SearchScope SINGLE_LEVEL = register(1, "one", Enum.SINGLE_LEVEL);
064
065    /** The scope is constrained to the search base entry and to all its subordinates. */
066    public static final SearchScope WHOLE_SUBTREE = register(2, "sub", Enum.WHOLE_SUBTREE);
067
068    /**
069     * The scope is constrained to all the subordinates of the search base
070     * entry, but does not include the search base entry itself (as wholeSubtree
071     * does).
072     */
073    public static final SearchScope SUBORDINATES = register(3, "subordinates", Enum.SUBORDINATES);
074
075    /**
076     * Returns the search scope having the specified integer value as defined in
077     * RFC 4511 section 4.5.1.2.
078     *
079     * @param intValue
080     *            The integer value of the search scope.
081     * @return The search scope, or {@code null} if there was no search scope
082     *         associated with {@code intValue}.
083     */
084    public static SearchScope valueOf(final int intValue) {
085        SearchScope result = null;
086        if (0 <= intValue && intValue < ELEMENTS.length) {
087            result = ELEMENTS[intValue];
088        }
089        if (result == null) {
090            result = new SearchScope(intValue, "unknown(" + intValue + ")", Enum.UNKNOWN);
091        }
092        return result;
093    }
094
095    /**
096     * Returns the search scope having the specified name as defined in RFC 4511
097     * section 4.5.1.2.
098     *
099     * @param name
100     *          the name of the search scope to return
101     * @return The search scope, or {@code null} if there was no search scope
102     *         associated with {@code name}.
103     * @throws NullPointerException
104     *           if name is null
105     */
106    public static SearchScope valueOf(String name) {
107        for (SearchScope searchScope : ELEMENTS) {
108            if (searchScope.name.equals(name)) {
109                return searchScope;
110            }
111        }
112        return null;
113    }
114
115    /**
116     * Returns an unmodifiable list containing the set of available search
117     * scopes indexed on their integer value as defined in RFC 4511 section
118     * 4.5.1.2.
119     *
120     * @return An unmodifiable list containing the set of available search
121     *         scopes.
122     */
123    public static List<SearchScope> values() {
124        return IMMUTABLE_ELEMENTS;
125    }
126
127    /**
128     * Creates and registers a new search scope with the application.
129     *
130     * @param intValue
131     *            The integer value of the search scope as defined in RFC 4511
132     *            section 4.5.1.2.
133     * @param name
134     *            The name of the search scope as defined in RFC 4516.
135     * @param searchScopeEnum
136     *            The enum equivalent for this search scope
137     * @return The new search scope.
138     */
139    private static SearchScope register(final int intValue, final String name, Enum searchScopeEnum) {
140        final SearchScope t = new SearchScope(intValue, name, searchScopeEnum);
141        ELEMENTS[intValue] = t;
142        return t;
143    }
144
145    private final int intValue;
146
147    private final String name;
148
149    private final Enum searchScopeEnum;
150
151    /** Prevent direct instantiation. */
152    private SearchScope(final int intValue, final String name, Enum searchScopeEnum) {
153        this.intValue = intValue;
154        this.name = name;
155        this.searchScopeEnum = searchScopeEnum;
156    }
157
158    @Override
159    public boolean equals(final Object obj) {
160        if (this == obj) {
161            return true;
162        } else if (obj instanceof SearchScope) {
163            return this.intValue == ((SearchScope) obj).intValue;
164        } else {
165            return false;
166        }
167    }
168
169    @Override
170    public int hashCode() {
171        return intValue;
172    }
173
174    /**
175     * Returns the integer value of this search scope as defined in RFC 4511
176     * section 4.5.1.2.
177     *
178     * @return The integer value of this search scope.
179     */
180    public int intValue() {
181        return intValue;
182    }
183
184    /**
185     * Returns the enum equivalent for this search scope.
186     *
187     * @return The enum equivalent for this search scope when a known mapping exists,
188     *         or {@link Enum#UNKNOWN} if this is an unknown search scope.
189     */
190    public Enum asEnum() {
191        return this.searchScopeEnum;
192    }
193
194    /**
195     * Returns the string representation of this search scope as defined in RFC
196     * 4516.
197     *
198     * @return The string representation of this search scope.
199     */
200    @Override
201    public String toString() {
202        return name;
203    }
204}