1 /*
   2  * Copyright (c) 1999, 2019, 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 
  26 package javax.naming.ldap;
  27 
  28 import javax.naming.*;
  29 import javax.naming.directory.*;
  30 
  31 import 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   * <h2>Request Controls</h2>
  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 
  90 public 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 }