1/*
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.naming.ldap;
27
28import javax.naming.*;
29import javax.naming.directory.*;
30
31import java.util.Hashtable;
32
33/**
34  * This class is the starting context for performing
35  * LDAPv3-style extended operations and controls.
36  *<p>
37  * See {@code javax.naming.InitialContext} and
38  * {@code javax.naming.InitialDirContext} for details on synchronization,
39  * and the policy for how an initial context is created.
40  *
41  * <h1>Request Controls</h1>
42  * When you create an initial context ({@code InitialLdapContext}),
43  * you can specify a list of request controls.
44  * These controls will be used as the request controls for any
45  * implicit LDAP "bind" operation performed by the context or contexts
46  * derived from the context. These are called <em>connection request controls</em>.
47  * Use {@code getConnectControls()} to get a context's connection request
48  * controls.
49  *<p>
50  * The request controls supplied to the initial context constructor
51  * are <em>not</em> used as the context request controls
52  * for subsequent context operations such as searches and lookups.
53  * Context request controls are set and updated by using
54  * {@code setRequestControls()}.
55  *<p>
56  * As shown, there can be two different sets of request controls
57  * associated with a context: connection request controls and context
58  * request controls.
59  * This is required for those applications needing to send critical
60  * controls that might not be applicable to both the context operation and
61  * any implicit LDAP "bind" operation.
62  * A typical user program would do the following:
63  *<blockquote><pre>
64  * InitialLdapContext lctx = new InitialLdapContext(env, critConnCtls);
65  * lctx.setRequestControls(critModCtls);
66  * lctx.modifyAttributes(name, mods);
67  * Controls[] respCtls =  lctx.getResponseControls();
68  *</pre></blockquote>
69  * It specifies first the critical controls for creating the initial context
70  * ({@code critConnCtls}), and then sets the context's request controls
71  * ({@code critModCtls}) for the context operation. If for some reason
72  * {@code lctx} needs to reconnect to the server, it will use
73  * {@code critConnCtls}. See the {@code LdapContext} interface for
74  * more discussion about request controls.
75  *<p>
76  * Service provider implementors should read the "Service Provider" section
77  * in the {@code LdapContext} class description for implementation details.
78  *
79  * @author Rosanna Lee
80  * @author Scott Seligman
81  * @author Vincent Ryan
82  *
83  * @see LdapContext
84  * @see javax.naming.InitialContext
85  * @see javax.naming.directory.InitialDirContext
86  * @see javax.naming.spi.NamingManager#setInitialContextFactoryBuilder
87  * @since 1.3
88  */
89
90public class InitialLdapContext extends InitialDirContext implements LdapContext {
91    private static final String
92        BIND_CONTROLS_PROPERTY = "java.naming.ldap.control.connect";
93
94    /**
95     * Constructs an initial context using no environment properties or
96     * connection request controls.
97     * Equivalent to {@code new InitialLdapContext(null, null)}.
98     *
99     * @throws  NamingException if a naming exception is encountered
100     */
101    public InitialLdapContext() throws NamingException {
102        super(null);
103    }
104
105    /**
106     * Constructs an initial context
107     * using environment properties and connection request controls.
108     * See {@code javax.naming.InitialContext} for a discussion of
109     * environment properties.
110     *
111     * <p> This constructor will not modify its parameters or
112     * save references to them, but may save a clone or copy.
113     * Caller should not modify mutable keys and values in
114     * {@code environment} after it has been passed to the constructor.
115     *
116     * <p> {@code connCtls} is used as the underlying context instance's
117     * connection request controls.  See the class description
118     * for details.
119     *
120     * @param environment
121     *          environment used to create the initial DirContext.
122     *          Null indicates an empty environment.
123     * @param connCtls
124     *          connection request controls for the initial context.
125     *          If null, no connection request controls are used.
126     *
127     * @throws  NamingException if a naming exception is encountered
128     *
129     * @see #reconnect
130     * @see LdapContext#reconnect
131     */
132    @SuppressWarnings("unchecked")
133    public InitialLdapContext(Hashtable<?,?> environment,
134                              Control[] connCtls)
135            throws NamingException {
136        super(true); // don't initialize yet
137
138        // Clone environment since caller owns it.
139        Hashtable<Object,Object> env = (environment == null)
140            ? new Hashtable<>(11)
141            : (Hashtable<Object,Object>)environment.clone();
142
143        // Put connect controls into environment.  Copy them first since
144        // caller owns the array.
145        if (connCtls != null) {
146            Control[] copy = new Control[connCtls.length];
147            System.arraycopy(connCtls, 0, copy, 0, connCtls.length);
148            env.put(BIND_CONTROLS_PROPERTY, copy);
149        }
150        // set version to LDAPv3
151        env.put("java.naming.ldap.version", "3");
152
153        // Initialize with updated environment
154        init(env);
155    }
156
157    /**
158     * Retrieves the initial LDAP context.
159     *
160     * @return The non-null cached initial context.
161     * @exception NotContextException If the initial context is not an
162     * instance of {@code LdapContext}.
163     * @exception NamingException If a naming exception was encountered.
164     */
165    private LdapContext getDefaultLdapInitCtx() throws NamingException{
166        Context answer = getDefaultInitCtx();
167
168        if (!(answer instanceof LdapContext)) {
169            if (answer == null) {
170                throw new NoInitialContextException();
171            } else {
172                throw new NotContextException(
173                    "Not an instance of LdapContext");
174            }
175        }
176        return (LdapContext)answer;
177    }
178
179// LdapContext methods
180// Most Javadoc is deferred to the LdapContext interface.
181
182    public ExtendedResponse extendedOperation(ExtendedRequest request)
183            throws NamingException {
184        return getDefaultLdapInitCtx().extendedOperation(request);
185    }
186
187    public LdapContext newInstance(Control[] reqCtls)
188        throws NamingException {
189            return getDefaultLdapInitCtx().newInstance(reqCtls);
190    }
191
192    public void reconnect(Control[] connCtls) throws NamingException {
193        getDefaultLdapInitCtx().reconnect(connCtls);
194    }
195
196    public Control[] getConnectControls() throws NamingException {
197        return getDefaultLdapInitCtx().getConnectControls();
198    }
199
200    public void setRequestControls(Control[] requestControls)
201        throws NamingException {
202            getDefaultLdapInitCtx().setRequestControls(requestControls);
203    }
204
205    public Control[] getRequestControls() throws NamingException {
206        return getDefaultLdapInitCtx().getRequestControls();
207    }
208
209    public Control[] getResponseControls() throws NamingException {
210        return getDefaultLdapInitCtx().getResponseControls();
211    }
212}
213