001/*
002 * Copyright 2015-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2015-2020 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2015-2020 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.util.json;
037
038
039
040import java.io.BufferedReader;
041import java.io.File;
042import java.io.FileInputStream;
043import java.io.FileReader;
044import java.io.InputStream;
045import java.io.IOException;
046import java.util.Arrays;
047import java.util.HashSet;
048
049import com.unboundid.ldap.sdk.BindRequest;
050import com.unboundid.ldap.sdk.LDAPConnection;
051import com.unboundid.ldap.sdk.LDAPConnectionPool;
052import com.unboundid.ldap.sdk.LDAPException;
053import com.unboundid.ldap.sdk.ResultCode;
054import com.unboundid.ldap.sdk.ServerSet;
055import com.unboundid.util.ByteStringBuffer;
056import com.unboundid.util.Debug;
057import com.unboundid.util.NotMutable;
058import com.unboundid.util.StaticUtils;
059import com.unboundid.util.ThreadSafety;
060import com.unboundid.util.ThreadSafetyLevel;
061
062import static com.unboundid.util.json.JSONMessages.*;
063
064
065
066/**
067 * This class provides a utility that may be used to obtain information that may
068 * be used to create LDAP connections to one or more servers from a definition
069 * contained in a JSON object.  This makes it easier to create applications that
070 * provide the information necessary for creating LDAP connections and
071 * connection pools in a JSON-formatted configuration file.
072 * <BR><BR>
073 * The JSON-based specification is organized into five sections:
074 * <OL>
075 *   <LI>
076 *     A "server-details" section that provides information about the directory
077 *     server(s) to access.  The specification supports accessing a single
078 *     server, as well as a number of schemes for establishing connections
079 *     across multiple servers.
080 *   </LI>
081 *   <LI>
082 *     A "communication-security" section that provides information that may be
083 *     used to secure communication using SSL or StartTLS.
084 *   </LI>
085 *   <LI>
086 *     A "connection-options" section that can be used customize a number of
087 *     connection-related options, like connect and response timeouts, whether
088 *     to follow referrals, whether to retrieve schema from the backend server
089 *     for client-side use, and whether to use synchronous mode for more
090 *     efficient communication if connections will not be used in an
091 *     asynchronous manner.
092 *   </LI>
093 *   <LI>
094 *     An "authentication-details" section that provides information for
095 *     authenticating connections using a number of mechanisms.
096 *   </LI>
097 *   <LI>
098 *     A "connection-pool-options" section that provides information to use to
099 *     customize the behavior to use for connection pools created from this
100 *     specification.
101 *   </LI>
102 * </OL>
103 * Each of these sections will be described in more detail below.
104 * <BR><BR>
105 * <H2>The "server-details" Section</H2>
106 * The JSON object that comprises the LDAP connection details specification must
107 * have a top-level "server-details" field whose value is a JSON object that
108 * provides information about the server(s) to which connections may be
109 * established.  The value of the "server-details" field must itself be a JSON
110 * object, and that object must have exactly one field, which depends on the
111 * mechanism that the LDAP SDK should use to select the target directory
112 * servers.
113 * <BR><BR>
114 * <B>The "server-details" Section for Connecting to a Single Server</B>
115 * <BR>
116 * When establishing a connection to a single server, the "server-details"
117 * value should be a JSON object that contains a "single-server" field whose
118 * value is a JSON object with "address" and "port" fields.  For example, the
119 * following is a valid specification that may be used to establish connections
120 * to the server at ldap.example.com on port 389:
121 * <PRE>
122 *   {
123 *     "server-details":
124 *     {
125 *       "single-server":
126 *       {
127 *         "address":"ldap.example.com",
128 *         "port":389
129 *       }
130 *     }
131 *   }
132 * </PRE>
133 * <BR>
134 * <B>The "server-details" Section for Selecting from a Set of Servers in a
135 * Round-Robin Manner</B>
136 * <BR>
137 * If you have a set of servers that you want to connect to in a round-robin
138 * manner (in which the LDAP SDK will maintain a circular list of servers and
139 * each new connection will go to the next server in the list), the
140 * "server-details" value should be a JSON object that contains a
141 * "round-robin-set" field whose value is a JSON object that contains a "server"
142 * field with an array of JSON objects, each of which contains "address" and
143 * "port" fields for a target server.  For example, the following is a valid
144 * specification that may be used to establish connections across the servers
145 * ldap1.example.com, ldap2.example.com, and ldap3.example.com, all on port 389:
146 * <PRE>
147 *   {
148 *     "server-details":
149 *     {
150 *       "round-robin-set":
151 *       {
152 *         "servers":
153 *         [
154 *           {
155 *             "address":"ldap1.example.com",
156 *             "port":389
157 *           },
158 *           {
159 *             "address":"ldap2.example.com",
160 *             "port":389
161 *           },
162 *           {
163 *             "address":"ldap2.example.com",
164 *             "port":389
165 *           }
166 *         ]
167 *       }
168 *     }
169 *   }
170 * </PRE>
171 * <BR>
172 * <B>The "server-details" Section for Selecting from a Set of Servers in a
173 * Fewest Connections Manner</B>
174 * <BR>
175 * If you have a set of servers that you want to connect to in a manner that
176 * selects the server with the fewest established connections (at least
177 * connections created from this specification), the "server-details" value
178 * should be a JSON object that contains a "fewest-connections-set" field whose
179 * value is a JSON object that contains a "server" field with an array of JSON
180 * objects, each of which contains "address" and "port" fields for a target
181 * server.  For example, the following is a valid specification that may be used
182 * to establish connections across the servers ldap1.example.com,
183 * ldap2.example.com, and ldap3.example.com, all on port 389:
184 * <PRE>
185 *   {
186 *     "server-details":
187 *     {
188 *       "fewest-connections-set":
189 *       {
190 *         "servers":
191 *         [
192 *           {
193 *             "address":"ldap1.example.com",
194 *             "port":389
195 *           },
196 *           {
197 *             "address":"ldap2.example.com",
198 *             "port":389
199 *           },
200 *           {
201 *             "address":"ldap2.example.com",
202 *             "port":389
203 *           }
204 *         ]
205 *       }
206 *     }
207 *   }
208 * </PRE>
209 * <BR>
210 * <B>The "server-details" Section for Selecting from a Set of Servers in a
211 * Fastest Connect Manner</B>
212 * <BR>
213 * If you have a set of servers that you want to connect to in a manner that
214 * attempts to minimize the time required to establish new connections (by
215 * simultaneously attempting to create connections to every server in the set
216 * and taking the first connection to be established), the "server-details"
217 * value should be a JSON object that contains a "fastest-connect-set" field
218 * whose value is a JSON object that contains a "server" field with an array of
219 * JSON objects, each of which contains "address" and "port" fields for a target
220 * server.  For example, the following is a valid specification that may be used
221 * to establish connections across the servers ldap1.example.com,
222 * ldap2.example.com, and ldap3.example.com, all on port 389:
223 * <PRE>
224 *   {
225 *     "server-details":
226 *     {
227 *       "fastest-connect-set":
228 *       {
229 *         "servers":
230 *         [
231 *           {
232 *             "address":"ldap1.example.com",
233 *             "port":389
234 *           },
235 *           {
236 *             "address":"ldap2.example.com",
237 *             "port":389
238 *           },
239 *           {
240 *             "address":"ldap2.example.com",
241 *             "port":389
242 *           }
243 *         ]
244 *       }
245 *     }
246 *   }
247 * </PRE>
248 * <BR>
249 * <B>The "server-details" Section for Selecting from a Set of Servers in a
250 * Failover Manner</B>
251 * <BR>
252 * If you have a set of servers that you want to connect to in a manner that
253 * attempts to consistently establish connections to the same server (as long as
254 * it is available, and use a consistent failover order if the preferred server
255 * isn't available), the "server-details" value should be a JSON object that
256 * contains a "failover-set" field whose value is a JSON object that contains a
257 * "failover-order" field that provides a list of the details to use in order
258 * to establish the connections.  For example, the following is a valid
259 * specification that may be used to always try to establish connections to
260 * ldap1.example.com:389, then try ldap2.example.com:389, and then try
261 * ldap3.example.com:389:
262 * <PRE>
263 *   {
264 *     "server-details":
265 *     {
266 *       "failover-set":
267 *       {
268 *         "failover-order":
269 *         [
270 *           {
271 *             "single-server":
272 *             {
273 *               "address":"ldap1.example.com",
274 *               "port":389
275 *             }
276 *           },
277 *           {
278 *             "single-server":
279 *             {
280 *               "address":"ldap2.example.com",
281 *               "port":389
282 *             }
283 *           },
284 *           {
285 *             "single-server":
286 *             {
287 *               "address":"ldap2.example.com",
288 *               "port":389
289 *             }
290 *           }
291 *         ]
292 *       }
293 *     }
294 *   }
295 * </PRE>
296 * The failover set actually has the ability to perform failover across any kind
297 * of set.  This is a powerful capability that can be useful to define a
298 * hierarchy of sets, for example for sets referring to servers in different
299 * data centers (e.g., to prefer connecting to one of the servers in the local
300 * data center over servers in a remote data center).  For example, the
301 * following is a valid specification that may be used to connect to the server
302 * with the fewest connections in the east data center, but if no east servers
303 * are available then it will fail over to select the server with the fewest
304 * connections in the west data center:
305 * <PRE>
306 *   {
307 *     "server-details":
308 *     {
309 *       "failover-set":
310 *       {
311 *         "failover-order":
312 *         [
313 *           {
314 *             "fewest-connections-set":
315 *             {
316 *               "servers":
317 *               [
318 *                 {
319 *                   "address":"ldap1.east.example.com",
320 *                   "port":389
321 *                 },
322 *                 {
323 *                   "address":"ldap2.east.example.com",
324 *                   "port":389
325 *                 }
326 *               ]
327 *             }
328 *           },
329 *           {
330 *             "fewest-connections-set":
331 *             {
332 *               "servers":
333 *               [
334 *                 {
335 *                   "address":"ldap1.west.example.com",
336 *                   "port":389
337 *                 },
338 *                 {
339 *                   "address":"ldap2.west.example.com",
340 *                   "port":389
341 *                 }
342 *               ]
343 *             }
344 *           }
345 *         ]
346 *       }
347 *     }
348 *   }
349 * </PRE>
350 * For connections that are part of a connection pool, failover sets have the
351 * ability to assign a different maximum connection age to connections created
352 * to a non-preferred server.  This can help allow failover connections to be
353 * migrated back to the preferred server more quickly once that server is
354 * available again.  If you wish to specify an alternate maximum connection age
355 * for connections to a non-preferred server, you may include the
356 * "maximum-failover-connection-age-millis" field in the "failover-set" object.
357 * The value of this field should be a number that is greater than zero to
358 * specify the maximum age (in milliseconds) for those connections, or a value
359 * of zero to indicate that they should not be subject to a maximum age.  If
360 * this field is not present, then these connections will be assigned the
361 * default maximum connection age configured for the pool.
362 * <BR><BR>
363 * <H2>The "communication-security" Section</H2>
364 * This section may be used to provide information about the type of security to
365 * use to protect communication with directory servers.  If the specification
366 * includes information about multiple servers, then all servers will use the
367 * same type of security.
368 * <BR><BR>
369 * If present, the "communication-security" field should have a value that is a
370 * JSON object.  This object must have a "security-type" field with one of the
371 * following values:
372 * <UL>
373 *   <LI>
374 *     "none" -- Indicates that no communication security should be used.  The
375 *     communication will not be encrypted.
376 *   </LI>
377 *   <LI>
378 *     "SSL" -- Indicates that all communication should be encrypted with the
379 *     SSL (secure sockets layer) protocol, or more likely its more secure
380 *     successor TLS (transport-layer security) protocol.  You can also specify
381 *     a value of "TLS" to use this type of security.
382 *   </LI>
383 *   <LI>
384 *     "StartTLS" -- Indicates that the connection will be initially established
385 *     in a non-secure manner, but will be immediately secured with the StartTLS
386 *     extended operation.
387 *   </LI>
388 * </UL>
389 * If you do not wish to use any form of communication security, then the
390 * "security-type" field is the only one that should be present.  For example,
391 * the following is a valid specification that will use unencrypted
392 * communication to the server ldap.example.com on port 389:
393 * <PRE>
394 *   {
395 *     "server-details":
396 *     {
397 *       "single-server":
398 *       {
399 *         "address":"ldap.example.com",
400 *         "port":389
401 *       }
402 *     },
403 *     "communication-security":
404 *     {
405 *       "security-type":"none"
406 *     }
407 *   }
408 * </PRE>
409 * <BR>
410 * If you wish to secure the communication with either SSL or StartTLS, then
411 * there are a number of other options that may be specified using fields in the
412 * "communication-security" object.  Those options fall into two basic
413 * categories:  fields that provide information about how the client should
414 * determine whether to trust the certificate presented by the server, and
415 * fields that provide information about whether the client should present its
416 * own certificate to the server.  The fields related to client trust include:
417 * <UL>
418 *   <LI>
419 *     "trust-all-certificates" -- Indicates whether the client should blindly
420 *     trust any certificate that the server presents to it.  Using blind trust
421 *     is convenient for testing and troubleshooting purposes, but is not
422 *     recommended for production use because it can leave the communication
423 *     susceptible to man-in-the-middle attacks.  If this field is present, then
424 *     it should have a boolean value.  If it is not present, a default value
425 *     of {@code false} will be assumed.  If it is present with a value of
426 *     {@code true}, then the "use-jvm-default-trust-store", "trust-store-file",
427 *     "trust-store-type", "trust-store-pin", and "trust-store-pin-file" fields
428 *     should not be used.
429 *   </LI>
430 *   <LI>
431 *     "use-jvm-default-trust-store" -- Indicates that certificates signed by an
432 *     authority listed in the JVM's default set of trusted issuers should be
433 *     trusted.  If this field is present, it should have a boolean value.  The
434 *     JVM-default trust store may be used on its own or in conjunction with a
435 *     trust store file.
436 *   </LI>
437 *   <LI>
438 *     "trust-store-file" -- Specifies the path to a trust store file (in JKS
439 *     or PKCS#12 format).  If this is present, then the presented certificate
440 *     will only be trusted if the trust store file contains information about
441 *     all of the issuers in the certificate chain.
442 *   </LI>
443 *   <LI>
444 *     "trust-store-type"  -- Indicates the format for the trust store file.
445 *     If this is present, then its value should be a string that is either
446 *     "JKS" or "PKCS12".  If it is not present, then a default trust store type
447 *     of "JKS" will be assumed.
448 *   </LI>
449 *   <LI>
450 *     "trust-store-pin" -- Specifies the PIN that should be used to access the
451 *     contents of the trust store.  If this field is present, then its value
452 *     should be a string that is the clear-text PIN.  If it is not present,
453 *     then the PIN may be read from a file specified using the
454 *     "trust-store-pin-file" field.  If neither the "trust-store-pin" field nor
455 *     the "trust-store-pin-file" field is present, then no PIN will be used
456 *     when attempting to access the trust store (and in many cases, no trust
457 *     store PIN will be required).
458 *   </LI>
459 *   <LI>
460 *     "trust-store-pin-file" -- Specifies the path to a file that contains the
461 *     PIN to use to access the contents of the trust store.  If this field is
462 *     present, then its value must be the path to a file containing a single
463 *     line, which is the clear-text PIN.  If it is not present, then the PIN
464 *     may be obtained from the "trust-store-pin" field.  If neither the
465 *     "trust-store-pin" field nor the "trust-store-pin-file" field is present,
466 *     then no PIN will be used when attempting to access the trust store (and
467 *     in many cases, no trust store PIN will be required).
468 *   </LI>
469 *   <LI>
470 *     "trust-expired-certificates" -- Indicates whether the client should
471 *     trust certificates that are not yet valid or that have expired.  If this
472 *     field is present, then its value must be a boolean.  If the value is
473 *     {@code true}, then the certificate validity dates will not be taken into
474 *     consideration when deciding whether to trust a certificate.  If the value
475 *     is {@code false}, then any certificate whose validity window does not
476 *     include the current time will not be trusted (even if
477 *     "trust-all-certificates" is {@code true}).  If this field is not present,
478 *     then a default of {@code false} will be assumed.
479 *   </LI>
480 *   <LI>
481 *     "verify-address-in-certificate" -- Indicates whether the client should
482 *     examine the information contained in the certificate to verify that the
483 *     address the client used to connect to the server matches address
484 *     information contained in the certificate (whether in the CN attribute of
485 *     the certificate's subject, or in a subjectAltName extension of type
486 *     dNSName, uniformResourceIdentifier, or iPAddress).  If this field is
487 *     present, then its value must be a boolean.  If it is absent, then a
488 *     default value of {@code false} will be assumed.
489 *   </LI>
490 * </UL>
491 * If none of the above fields are provided, then the JVM's default trust
492 * mechanism will be used.  This will generally only trust certificates signed
493 * by a well-known certification authority.
494 * <BR><BR>
495 * The fields related to presenting a client certificate include:
496 * <UL>
497 *   <LI>
498 *     "key-store-file" -- Specifies the path to a key store file (in JKS or
499 *     PKCS#12 format) that contains the certificate that the client should
500 *     present to the server.  If this is present, then the value must be a
501 *     string that is the path to the key store file.  If it is not present,
502 *     then no key store file will be used.
503 *   </LI>
504 *   <LI>
505 *     "key-store-type" -- Specifies the type of key store that should be used.
506 *     If this is present, then its value must be a string, and that string
507 *     should be "JKS" or "PKCS12" (if a "key-store-file" value is present), or
508 *     "PKCS11" (if the client certificate is contained in a security module
509 *     accessible via the PKCS#11 API.  If this field is not present but a
510 *     "key-store-file" value is provided, then a default value of "JKS" will be
511 *     assumed.
512 *   </LI>
513 *   <LI>
514 *     "key-store-pin" -- Specifies the PIN that should be used to access the
515 *     contents of the key store.  If this field is present, then its value
516 *     should be a string that is the clear-text PIN.  If it is not present,
517 *     then the PIN may be read from a file specified using the
518 *     "key-store-pin-file" field.  If neither the "key-store-pin" field nor the
519 *     "key-store-pin-file" field is present, then no PIN will be used when
520 *     attempting to access the key store (although key stores generally require
521 *     a PIN in order to access private key information).
522 *   </LI>
523 *   <LI>
524 *     "key-store-pin-file" -- Specifies the path to a file containing the PIN
525 *     that should be used to access the contents of the key store.  If this
526 *     field is present, then its value should be the path to a file containing
527 *     the clear-text PIN.  If it is not present, then the PIN may be obtained
528 *     from the "key-store-pin" field.  If neither the "key-store-pin" field nor
529 *     the "key-store-pin-file" field is present, then no PIN will be used when
530 *     attempting to access the key store (although key stores generally require
531 *     a PIN in order to access private key information).
532 *   </LI>
533 *   <LI>
534 *     "client-certificate-alias" -- Specifies the alias (also known as the
535 *     nickname) of the client certificate that should be presented to the
536 *     directory server.  If this field is present, then its value should be a
537 *     string that is the alias for a valid certificate that exists in the
538 *     key store.  If this field is not present, then the JVM will automatically
539 *     attempt to select a suitable client certificate.
540 *   </LI>
541 * </UL>
542 * If none of the above fields are provided, then the client will not attempt to
543 * present a certificate to the server.
544 * <BR><BR>
545 * The following example demonstrates a simple specification that can be used to
546 * establish SSL-based connections to a single server.  The client will trust
547 * any certificates signed by one of the JVM's default issuers, or any
548 * certificate contained in or signed by a certificate contained in the
549 * specified trust store file.  As no key store is provided, the client will not
550 * attempt to present its own certificate to the server.
551 * <PRE>
552 *   {
553 *     "server-details":
554 *     {
555 *       "single-server":
556 *       {
557 *         "address":"ldap.example.com",
558 *         "port":636
559 *       }
560 *     },
561 *     "communication-security":
562 *     {
563 *       "security-type":"SSL",
564 *       "use-jvm-default-trust-store":true,
565 *       "trust-store-file":"/path/to/trust-store.jks",
566 *       "trust-store-type":"JKS",
567 *       "verify-address-in-certificate":true
568 *     }
569 *   }
570 * </PRE>
571 * <BR>
572 * The "communication-security" field is optional, and if it is omitted from the
573 * specification then it will be equivalent to including it with a
574 * "security-type" value of "none".
575 * <BR><BR>
576 * <H2>The "connection-options" Section</H2>
577 * The "connection-options" section may be used to provide information about a
578 * number of settings that may be used in the course of establishing a
579 * connection, or that may affect the behavior of the connection.  The value
580 * of the "connection-options" field must be a JSON object, and the following
581 * fields may appear in that object:
582 * <UL>
583 *   <LI>
584 *     "connect-timeout-millis" -- Specifies the maximum length of time (in
585 *     milliseconds) that a connection attempt may block while waiting for the
586 *     connection to be established.  If this field is present, then its value
587 *     must be a positive integer to specify the timeout, or a value of zero to
588 *     indicate that no timeout should be enforced by the LDAP SDK.  Note that
589 *     the underlying operating system may enforce its own connect timeout, and
590 *     if that value is smaller than the LDAP SDK timeout then the operating
591 *     system's timeout value will be used.  If this field is not present, then
592 *     a default of 60000 (1 minute) will be used.
593 *   </LI>
594 *   <LI>
595 *     "default-response-timeout-millis" -- Specifies the default timeout (in
596 *     milliseconds) that will be used when waiting for a response to a request
597 *     sent to the server.  If this field is present, then its value must be a
598 *     positive integer to specify the timeout, or a value of zero to indicate
599 *     that no timeout should be enforced.  If this field is not present, then a
600 *     default of 300000 (5 minutes) will be used.  Note that this default
601 *     response timeout can be overridden on a per-request basis using the
602 *     {@code setResponseTimeoutMillis} method provided by the request object.
603 *   </LI>
604 *   <LI>
605 *     "follow-referrals" -- Indicates whether the LDAP SDK should automatically
606 *     attempt to follow any referrals that are returned during processing.  If
607 *     this field is present, the value should be a boolean.  If it is absent,
608 *     then a default  of {@code false} will be assumed.
609 *   </LI>
610 *   <LI>
611 *     "use-schema" -- Indicates whether the LDAP SDK should attempt to retrieve
612 *     schema information from the directory server upon establishing a
613 *     connection to that server, and should then use that schema information
614 *     for more accurate client-side matching operations.  If present, this
615 *     field should have a boolean value.  If it is not present, then a default
616 *     value of {@code false} will be used.
617 *   </LI>
618 *   <LI>
619 *     "use-synchronous-mode" -- Indicates whether connections should be created
620 *     in synchronous mode, which may be more efficient and less resource
621 *     intensive than connections not created in synchronous mode, but may only
622 *     be used if no attempt will be made to issue asynchronous requests over
623 *     the connection, or to attempt to use the connection simultaneously by
624 *     multiple threads.  If this field is present, then its value must be a
625 *     boolean.  If it is not present, then a default value of {@code false}
626 *     will be used.
627 *   </LI>
628 * </UL>
629 * <BR>
630 * The "connection-options" field is optional, and if it is omitted from the
631 * specification then the default values will be used for all options.
632 * <BR><BR>
633 * <H2>The "authentication-details" Section</H2>
634 * The "authentication-details" section may be used to provide information for
635 * authenticating the connections that are created.  The value of the
636 * "authentication-details" field must be a JSON object, and it must include an
637 * "authentication-type" field to specify the mechanism to use to authenticate.
638 * The selected authentication type dictates the other fields that may be
639 * present in the object.
640 * <BR><BR>
641 * <B>The "none" Authentication Type</B>
642 * <BR>
643 * If no authentication should be performed, then the "authentication-type"
644 * value should be "none".  No other fields should be specified in the
645 * "authentication-details".  For example:
646 * <PRE>
647 *   {
648 *     "server-details":
649 *     {
650 *       "single-server":
651 *       {
652 *         "address":"ldap.example.com",
653 *         "port":389
654 *       }
655 *     },
656 *     "authentication-details":
657 *     {
658 *       "authentication-type":"none"
659 *     }
660 *   }
661 * </PRE>
662 * <BR>
663 * <B>The "simple" Authentication Type</B>
664 * <BR>
665 * If you wish to authenticate connections with an LDAP simple bind, then you
666 * can specify an "authentication-type" value of "simple".  The following
667 * additional fields may be included in the "authentication-details" object for
668 * this authentication type:
669 * <UL>
670 *   <LI>
671 *     "dn" -- The DN to use to bind to the server.  This field must be present,
672 *     and its value must be a string containing the bind DN, or an empty string
673 *     to indicate anonymous simple authentication.
674 *   </LI>
675 *   <LI>
676 *     "password" -- The password to use to bind to the server.  If this field
677 *     is present, then its value must be a string that contains the clear-text
678 *     password, or an empty string to indicate anonymous simple
679 *     authentication.  If it is not provided, then the "password-file" field
680 *     must be used to specify the path to a file containing the bind password.
681 *   </LI>
682 *   <LI>
683 *     "password-file" -- The path to a file containing the password to use to
684 *     bind to the server.  If this field is present, then its value must be a
685 *     string that represents the path to a file containing a single line that
686 *     contains the clear-text password.  If it is not provided, then the
687 *     "password" field must be used to specify the password.
688 *   </LI>
689 * </UL>
690 * For example:
691 * <PRE>
692 *   {
693 *     "server-details":
694 *     {
695 *       "single-server":
696 *       {
697 *         "address":"ldap.example.com",
698 *         "port":389
699 *       }
700 *     },
701 *     "authentication-details":
702 *     {
703 *       "authentication-type":"simple",
704 *       "dn":"uid=john.doe,ou=People,dc=example,dc=com",
705 *       "password-file":"/path/to/password.txt"
706 *     }
707 *   }
708 * </PRE>
709 * <BR>
710 * <B>The "CRAM-MD5" Authentication Type</B>
711 * If you wish to authenticate connections with the CRAM-MD5 SASL mechanism,
712 * then you can specify an "authentication-type" value of "CRAM-MD5".  The
713 * following additional fields may be included in the "authentication-details"
714 * object for this authentication type:
715 * <UL>
716 *   <LI>
717 *     "authentication-id" -- The authentication ID to use to bind.  This field
718 *     must be present, and its value must be a string containing the
719 *     authentication ID.  Authentication ID values typically take the form
720 *     "dn:" followed by the user DN, or "u:" followed by the username.
721 *   </LI>
722 *   <LI>
723 *     "password" -- The password to use to bind to the server.  If this field
724 *     is present, then its value must be a string that contains the clear-text
725 *     password, or an empty string to indicate anonymous simple
726 *     authentication.  If it is not provided, then the "password-file" field
727 *     must be used to specify the path to a file containing the bind password.
728 *   </LI>
729 *   <LI>
730 *     "password-file" -- The path to a file containing the password to use to
731 *     bind to the server.  If this field is present, then its value must be a
732 *     string that represents the path to a file containing a single line that
733 *     contains the clear-text password.  If it is not provided, then the
734 *     "password" field must be used to specify the password.
735 *   </LI>
736 * </UL>
737 * For Example:
738 * <PRE>
739 *   {
740 *     "server-details":
741 *     {
742 *       "single-server":
743 *       {
744 *         "address":"ldap.example.com",
745 *         "port":389
746 *       }
747 *     },
748 *     "authentication-details":
749 *     {
750 *       "authentication-type":"CRAM-MD5",
751 *       "authentication-id":"u:john.doe",
752 *       "password-file":"/path/to/password.txt"
753 *     }
754 *   }
755 * </PRE>
756 * <BR>
757 * <B>The "DIGEST-MD5" Authentication Type</B>
758 * If you wish to authenticate connections with the DIGEST-MD5 SASL mechanism,
759 * then you can specify an "authentication-type" value of "DIGEST-MD5".  The
760 * following additional fields may be included in the "authentication-details"
761 * object for this authentication type:
762 * <UL>
763 *   <LI>
764 *     "authentication-id" -- The authentication ID to use to bind.  This field
765 *     must be present, and its value must be a string containing the
766 *     authentication ID.  Authentication ID values typically take the form
767 *     "dn:" followed by the user DN, or "u:" followed by the username.
768 *   </LI>
769 *   <LI>
770 *     "authorization-id" -- The alternate authorization identity to use for the
771 *     connection after the bind has completed.  If present, the value must be
772 *     a string containing the desired authorization identity.  If this field is
773 *     absent, then no alternate authorization identity will be used.
774 *   </LI>
775 *   <LI>
776 *     "password" -- The password to use to bind to the server.  If this field
777 *     is present, then its value must be a string that contains the clear-text
778 *     password, or an empty string to indicate anonymous simple
779 *     authentication.  If it is not provided, then the "password-file" field
780 *     must be used to specify the path to a file containing the bind password.
781 *   </LI>
782 *   <LI>
783 *     "password-file" -- The path to a file containing the password to use to
784 *     bind to the server.  If this field is present, then its value must be a
785 *     string that represents the path to a file containing a single line that
786 *     contains the clear-text password.  If it is not provided, then the
787 *     "password" field must be used to specify the password.
788 *   </LI>
789 *   <LI>
790 *     "realm" -- The realm to use for the bind request.  If this field is
791 *     present, then its value must be a string containing the name of the
792 *     realm.  If it is not provided, then the realm will not be included in the
793 *     bind request.
794 *   </LI>
795 *   <LI>
796 *     "qop" -- The allowed quality of protection value(s) that may be used for
797 *     the bind operation.  If this field is present, then its value may be a
798 *     single string or an array of strings indicating the allowed QoP values.
799 *     Allowed values include "auth" (for just authentication), "auth-int" (for
800 *     authentication followed by integrity protection for subsequent
801 *     communication on the connection), and "auth-conf" (for authentication
802 *     followed by confidentiality for subsequent communication on the
803 *     connection).  If this field is not present, then a default value of
804 *     "auth" will be assumed.
805 *   </LI>
806 * </UL>
807 * For Example:
808 * <PRE>
809 *   {
810 *     "server-details":
811 *     {
812 *       "single-server":
813 *       {
814 *         "address":"ldap.example.com",
815 *         "port":389
816 *       }
817 *     },
818 *     "authentication-details":
819 *     {
820 *       "authentication-type":"DIGEST-MD5",
821 *       "authentication-id":"u:john.doe",
822 *       "password-file":"/path/to/password.txt"
823 *     }
824 *   }
825 * </PRE>
826 * <BR>
827 * <B>The "EXTERNAL" Authentication Type</B>
828 * If you wish to authenticate connections with the EXTERNAL SASL mechanism,
829 * then you can specify an "authentication-type" value of "EXTERNAL".  The
830 * connection must be secured with SSL or StartTLS, and the following additional
831 * field may be present in the "authentication-details" object:
832 * <UL>
833 *   <LI>
834 *     "authorization-id" -- The authorization identity for the bind request.
835 *     If this field is present, then it must be a string containing the
836 *     desired authorization ID, or an empty string if the server should
837 *     determine the authorization identity.  If this field is omitted, then
838 *     the bind request will not include any SASL credentials, which may be
839 *     required for use with some servers that cannot handle the possibility of
840 *     an authorization ID in the bind request.
841 *   </LI>
842 * </UL>
843 * For Example:
844 * <PRE>
845 *   {
846 *     "server-details":
847 *     {
848 *       "single-server":
849 *       {
850 *         "address":"ldap.example.com",
851 *         "port":636
852 *       }
853 *     },
854 *     "communication-security":
855 *     {
856 *       "security-type":"SSL",
857 *       "use-jvm-default-trust-store":true,
858 *       "trust-store-file":"/path/to/trust-store.jks",
859 *       "trust-store-type":"JKS",
860 *       "verify-address-in-certificate":true
861 *     },
862 *     "authentication-details":
863 *     {
864 *       "authentication-type":"EXTERNAL",
865 *       "authorization-id":""
866 *     }
867 *   }
868 * </PRE>
869 * <BR>
870 * <B>The "GSSAPI" Authentication Type</B>
871 * If you wish to authenticate connections with the GSSAPI SASL mechanism,
872 * then you can specify an "authentication-type" value of "GSSAPI".  The
873 * following additional fields may be included in the "authentication-details"
874 * object for this authentication type:
875 * <UL>
876 *   <LI>
877 *     "authentication-id" -- The authentication ID to use to bind.  This field
878 *     must be present, and its value must be a string containing the
879 *     authentication ID.  Authentication ID values for a GSSAPI bind request
880 *     are typically the Kerberos principal for the user to authenticate.
881 *   </LI>
882 *   <LI>
883 *     "authorization-id" -- The alternate authorization identity to use for the
884 *     connection after the bind has completed.  If present, the value must be
885 *     a string containing the desired authorization identity.  If this field is
886 *     absent, then no alternate authorization identity will be used.
887 *   </LI>
888 *   <LI>
889 *     "password" -- The password to use to bind to the server.  If this field
890 *     is present, then its value must be a string that contains the clear-text
891 *     password, or an empty string to indicate anonymous simple
892 *     authentication.  If it is not provided, then the "password-file" field
893 *     may be used to specify the path to a file containing the bind password.
894 *     If authentication will require the use of cached credentials, then the
895 *     password may be omitted.
896 *   </LI>
897 *   <LI>
898 *     "password-file" -- The path to a file containing the password to use to
899 *     bind to the server.  If this field is present, then its value must be a
900 *     string that represents the path to a file containing a single line that
901 *     contains the clear-text password.  If it is not provided, then the
902 *     "password" field may be used to specify the password.  If authentication
903 *     will require the use of cached credentials, then the password may be
904 *     omitted.
905 *   </LI>
906 *   <LI>
907 *     "realm" -- The realm to use for the bind request.  If this field is
908 *     present, then its value must be a string containing the name of the
909 *     realm.  If it is not provided, then the JVM will attempt to determine the
910 *     realm from the underlying system configuration.
911 *   </LI>
912 *   <LI>
913 *     "qop" -- The allowed quality of protection value(s) that may be used for
914 *     the bind operation.  If this field is present, then its value may be a
915 *     single string or an array of strings indicating the allowed QoP values.
916 *     Allowed values include "auth" (for just authentication), "auth-int" (for
917 *     authentication followed by integrity protection for subsequent
918 *     communication on the connection), and "auth-conf" (for authentication
919 *     followed by confidentiality for subsequent communication on the
920 *     connection).  If this field is not present, then a default value of
921 *     "auth" will be assumed.
922 *   </LI>
923 *   <LI>
924 *     "kdc-address" -- The address of the Kerberos KDC to use during
925 *     authentication.  If this field is present, then its value must be a
926 *     string containing the target address.  If it is not provided, then the
927 *     JVM will attempt to determine the address of the KDC from the underlying
928 *     system configuration.
929 *   </LI>
930 *   <LI>
931 *     "config-file-path" --  The path to a JAAS configuration file to use for
932 *     bind processing.  If this field is present, then its value must be a
933 *     string containing the path to a valid JAAS configuration file.  If it is
934 *     not provided, a temporary JAAS configuration file will be created for the
935 *     bind operation.
936 *   </LI>
937 *   <LI>
938 *     "renew-tgt" -- Indicates whether successful authentication should attempt
939 *     to renew the ticket-granting ticket for an existing session.  If this
940 *     field is present, then its value must be a boolean.  If it is not
941 *     provided, then a default of {@code false} will be assumed.
942 *   </LI>
943 *   <LI>
944 *     "require-cached-credentials" -- Indicates whether the authentication
945 *     process should require the use of cached credentials leveraged from an
946 *     existing Kerberos session rather than try to create a new session.  if
947 *     this field is present, then its value must be a boolean.  If it is not
948 *     provided, then a default of {@code false} will be assumed.
949 *   </LI>
950 *   <LI>
951 *     "use-ticket-cache" -- Indicates whether the authentication process should
952 *     leverage a ticket cache in order to leverage an existing Kerberos
953 *     session if the user has already authenticated to the KDC.  If present,
954 *     then its value must be a boolean.  If it is not provided, then a default
955 *     of {@code true} will be used.
956 *   </LI>
957 *   <LI>
958 *     "ticket-cache-path" -- Specifies the path to the Kerberos ticket cache to
959 *     use.  If this is provided, its value must be a string with the path to
960 *     the desired ticket cache.  If it is not provided, then the JVM will
961 *     attempt to determine the appropriate ticket cache from the underlying
962 *     system configuration.
963 *   </LI>
964 *   <LI>
965 *     "use-subject-credentials-only" -- Indicates whether authentication should
966 *     require the client will be required to use credentials that match the
967 *     current subject.  If it is provided, then the value must be a boolean.
968 *     If it is not provided, then a default of {@code true} will be assumed.
969 *   </LI>
970 * </UL>
971 * For Example:
972 * <PRE>
973 *   {
974 *     "server-details":
975 *     {
976 *       "single-server":
977 *       {
978 *         "address":"ldap.example.com",
979 *         "port":389
980 *       }
981 *     },
982 *     "authentication-details":
983 *     {
984 *       "authentication-type":"GSSAPI",
985 *       "authentication-id":"john.doe@EXAMPLE.COM",
986 *       "password-file":"/path/to/password.txt",
987 *       "renew-tgt":true
988 *     }
989 *   }
990 * </PRE>
991 * <BR>
992 * <B>The "PLAIN" Authentication Type</B>
993 * If you wish to authenticate connections with the PLAIN SASL mechanism,
994 * then you can specify an "authentication-type" value of "PLAIN".  The
995 * following additional fields may be included in the "authentication-details"
996 * object for this authentication type:
997 * <UL>
998 *   <LI>
999 *     "authentication-id" -- The authentication ID to use to bind.  This field
1000 *     must be present, and its value must be a string containing the
1001 *     authentication ID.  Authentication ID values typically take the form
1002 *     "dn:" followed by the user DN, or "u:" followed by the username.
1003 *   </LI>
1004 *   <LI>
1005 *     "authorization-id" -- The alternate authorization identity to use for the
1006 *     connection after the bind has completed.  If present, the value must be
1007 *     a string containing the desired authorization identity.  If this field is
1008 *     absent, then no alternate authorization identity will be used.
1009 *   </LI>
1010 *   <LI>
1011 *     "password" -- The password to use to bind to the server.  If this field
1012 *     is present, then its value must be a string that contains the clear-text
1013 *     password, or an empty string to indicate anonymous simple
1014 *     authentication.  If it is not provided, then the "password-file" field
1015 *     must be used to specify the path to a file containing the bind password.
1016 *   </LI>
1017 *   <LI>
1018 *     "password-file" -- The path to a file containing the password to use to
1019 *     bind to the server.  If this field is present, then its value must be a
1020 *     string that represents the path to a file containing a single line that
1021 *     contains the clear-text password.  If it is not provided, then the
1022 *     "password" field must be used to specify the password.
1023 *   </LI>
1024 * </UL>
1025 * For Example:
1026 * <PRE>
1027 *   {
1028 *     "server-details":
1029 *     {
1030 *       "single-server":
1031 *       {
1032 *         "address":"ldap.example.com",
1033 *         "port":389
1034 *       }
1035 *     },
1036 *     "authentication-details":
1037 *     {
1038 *       "authentication-type":"PLAIN",
1039 *       "authentication-id":"dn:uid=john.doe,ou=People,dc=example,dc=com",
1040 *       "password-file":"/path/to/password.txt"
1041 *     }
1042 *   }
1043 * </PRE>
1044 * <BR>
1045 * The "authentication-details" field is optional, and if it is omitted from the
1046 *  specification then no authentication will be performed.
1047 * <BR><BR>
1048 * <H2>The "connection-pool-options" Section</H2>
1049 * The "connection-pool-options" section may be used to provide information
1050 * about a number of settings that may be used in the course of creating or
1051 * maintaining a connection pool.  The value of the "connection-pool-options"
1052 * field must be a JSON object, and the following fields may appear in that
1053 * object:
1054 * <UL>
1055 *   <LI>
1056 *     "create-if-necessary" -- Indicates whether the connection pool should
1057 *     create a new connection if one is needed but none are available.  If
1058 *     present, the value must be a boolean.  If it is absent, then a default
1059 *     of {@code true} will be assumed.
1060 *   </LI>
1061 *   <LI>
1062 *     "health-check-get-entry-dn" -- The DN of an entry that should be
1063 *     retrieved during health check processing.  If present, the value must be
1064 *     a string that represents the DN of the entry to retrieve, or an empty
1065 *     string to indicate that the server root DSE should be retrieved.  If this
1066 *     field is absent, then no entry will be retrieved during health check
1067 *     processing.
1068 *   </LI>
1069 *   <LI>
1070 *     "health-check-get-entry-maximum-response-time-millis" -- The maximum
1071 *     length of time in milliseconds to wait for the entry to be returned in a
1072 *     get entry health check.  If present, the value must be a positive
1073 *     integer.  If it is not provided, then a default of 10000 (ten seconds)
1074 *     will be used.
1075 *   </LI>
1076 *   <LI>
1077 *     "initial-connect-threads" -- The number of threads to use when creating
1078 *     the initial set of connections for the pool.  If this field is present,
1079 *     then the value must be a positive integer, with a value of one indicating
1080 *     that connection should be created in a single-threaded manner, and a
1081 *     value greater than one indicating that the initial connections should be
1082 *     established in parallel.  If it is not provided, then a default of one
1083 *     will be used.
1084 *   </LI>
1085 *   <LI>
1086 *     "invoke-background-health-checks" -- Indicates whether the connection
1087 *     pool should periodically invoke health check processing on idle
1088 *     connections.  If this field is present, then its value must be a boolean.
1089 *     If it is not present, then a default of {@code true} will be assumed.
1090 *   </LI>
1091 *   <LI>
1092 *     "invoke-checkout-health-checks" -- Indicates whether the connection pool
1093 *     should invoke health check processing on connections just before they are
1094 *     checked out of the pool to ensure that they are valid.  If this field is
1095 *     present, then its value must be a boolean.  If it is not present, then a
1096 *     default of {@code false} will be assumed.
1097 *   </LI>
1098 *   <LI>
1099 *     "invoke-create-health-checks" -- Indicates whether the connection pool
1100 *     should invoke health check processing on connections just after they are
1101 *     created.  If this field is present, then its value must be a boolean.  If
1102 *     it is not present, then a default of {@code false} will be assumed.
1103 *   </LI>
1104 *   <LI>
1105 *     "invoke-authentication-health-checks" -- Indicates whether the connection
1106 *     pool should invoke health check processing on connections just after they
1107 *     have been authenticated.  This includes after a successful bind on a
1108 *     newly-created connection, and after calls to the connection pool's
1109 *     {@code bindAndRevertAuthentication} and
1110 *     {@code releaseAndReAuthenticateConnection} methods.  If this field is
1111 *     present, then its value must be a boolean.  If it is not present, then a
1112 *     default of {@code false} will be assumed.
1113 *   </LI>
1114 *   <LI>
1115 *     "invoke-exception-health-checks" -- Indicates whether the connection pool
1116 *     should invoke health check processing on connections just after an
1117 *     exception is caught that might indicate that the connection is no longer
1118 *     valid.  Note that this only applies to exceptions caught during
1119 *     operations processed directly against the connection pool and not to
1120 *     exceptions caught on a connection checked out of the pool.  If this field
1121 *     is present, then its value must be a boolean.  If it is not present, then
1122 *     a default of {@code true} will be assumed.
1123 *   </LI>
1124 *   <LI>
1125 *     "invoke-release-health-checks" -- Indicates whether the connection pool
1126 *     should invoke health check processing on connections just before they are
1127 *     released back to the pool to ensure that they are valid.  If this field
1128 *     is present, then its value must be a boolean.  If it is not present, then
1129 *     a default of {@code false} will be assumed.
1130 *   </LI>
1131 *   <LI>
1132 *     "maximum-connection-age-millis" -- Specifies the maximum length of time
1133 *     (in milliseconds) that a connection should be allowed to remain
1134 *     established before it is eligible to be closed and replaced with a
1135 *     newly-created connection.  If present, then the value must be a positive
1136 *     integer to specify the maximum age, or zero to indicate that no maximum
1137 *     age should be applied.  If it is not present, then a default value of
1138 *     zero will be used.
1139 *   </LI>
1140 *   <LI>
1141 *     "maximum-defunct-replacement-connection-age-millis" -- Specifies the
1142 *     maximum connection age (in milliseconds) that should be used for
1143 *     connections created to replace a defunct connection.  If present, then
1144 *     the value must be a positive integer to specify the maximum age, or zero
1145 *     to indicate that no maximum age should be applied.  If it is not present,
1146 *     then the value of the "maximum-connection-age-millis" field will be used
1147 *     for connections created as replacements for defunct connections.
1148 *   </LI>
1149 *   <LI>
1150 *     "maximum-wait-time-millis" -- Specifies the maximum length of time (in
1151 *     milliseconds) that the pool should wait for a connection to be released
1152 *     if one is needed but none are immediately available.  If present, then
1153 *     this value must be a positive integer to specify the length of time to
1154 *     wait, or zero to indicate that it should not wait at all.  If it is not
1155 *     provided, then a default value of zero will be used.
1156 *   </LI>
1157 *   <LI>
1158 *     "retry-failed-operations-due-to-invalid-connections" -- Indicates whether
1159 *     the pool should automatically attempt to retry operations attempted
1160 *     directly against the pool (but not for connections checked out of the
1161 *     pool) if the initial attempt fails in a manner that may indicate that the
1162 *     connection is no longer valid.  If this field is present, then its value
1163 *     may be either a boolean to indicate whether to enable retry for all types
1164 *     of operations or no operations, or it may be an array of strings
1165 *     indicating the operation types ("add", "bind", "compare", "delete",
1166 *     "extended", "modify", "modify-dn", or "search") that should be retried
1167 *     in the event of a failure.  If this field is not present, then no
1168 *     automatic retry will be attempted.
1169 *   </LI>
1170 * </UL>
1171 * <BR>
1172 * The "connection-pool-options" field is optional, and if it is omitted from
1173 * the specification then the default values will be used for all options.
1174 */
1175@NotMutable()
1176@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
1177public final class LDAPConnectionDetailsJSONSpecification
1178{
1179  /**
1180   * The name of the top-level field that may be used to provide information to
1181   * use to authenticate connections to the server.
1182   */
1183  static final String FIELD_AUTHENTICATION_DETAILS = "authentication-details";
1184
1185
1186
1187  /**
1188   * The name of the top-level field that may be used to provide information
1189   * about the type of communication security that should be used.
1190   */
1191  static final String FIELD_COMMUNICATION_SECURITY = "communication-security";
1192
1193
1194
1195  /**
1196   * The name of the top-level field that may be used to provide information
1197   * about options that should be set when establishing connections.
1198   */
1199  static final String FIELD_CONNECTION_OPTIONS = "connection-options";
1200
1201
1202
1203  /**
1204   * The name of the top-level field that may be used to provide information
1205   * about options that should be set when creating a connection pool.
1206   */
1207  static final String FIELD_CONNECTION_POOL_OPTIONS =
1208       "connection-pool-options";
1209
1210
1211
1212  /**
1213   * The name of the top-level field that may be used to provide information
1214   * about the directory server(s) to which the connection should be
1215   * established.
1216   */
1217  static final String FIELD_SERVER_DETAILS = "server-details";
1218
1219
1220
1221  // The bind request that will be used to authenticate connections.
1222  private final BindRequest bindRequest;
1223
1224  // The processed connection pool options portion of the specification.
1225  private final ConnectionPoolOptions connectionPoolOptionsSpec;
1226
1227  // The processed security options portion of the specification.
1228  private final SecurityOptions securityOptionsSpec;
1229
1230  // The server set that will be used to create connections.
1231  private final ServerSet serverSet;
1232
1233
1234
1235  /**
1236   * Creates a new LDAP connection details object from the specification
1237   * contained in the provided JSON object.
1238   *
1239   * @param  connectionDetailsObject  The JSON object that contains information
1240   *                                  that may be used to create LDAP
1241   *                                  connections.
1242   *
1243   * @throws  LDAPException  If the provided JSON object does not contain a
1244   *                         valid connection details specification.
1245   */
1246  public LDAPConnectionDetailsJSONSpecification(
1247              final JSONObject connectionDetailsObject)
1248         throws LDAPException
1249  {
1250    validateTopLevelFields(connectionDetailsObject);
1251
1252    try
1253    {
1254      securityOptionsSpec = new SecurityOptions(connectionDetailsObject);
1255    }
1256    catch (final LDAPException le)
1257    {
1258      Debug.debugException(le);
1259      throw new LDAPException(le.getResultCode(),
1260           ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1261                FIELD_COMMUNICATION_SECURITY, le.getMessage()),
1262           le);
1263    }
1264
1265    final ConnectionOptions connectionOptionsSpec;
1266    try
1267    {
1268      connectionOptionsSpec = new ConnectionOptions(connectionDetailsObject);
1269    }
1270    catch (final LDAPException le)
1271    {
1272      Debug.debugException(le);
1273      throw new LDAPException(le.getResultCode(),
1274           ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1275                FIELD_CONNECTION_OPTIONS, le.getMessage()),
1276           le);
1277    }
1278
1279    try
1280    {
1281      final ServerDetails serverDetailsSpec =
1282           new ServerDetails(connectionDetailsObject, securityOptionsSpec,
1283                connectionOptionsSpec);
1284      serverSet = serverDetailsSpec.getServerSet();
1285    }
1286    catch (final LDAPException le)
1287    {
1288      Debug.debugException(le);
1289      throw new LDAPException(le.getResultCode(),
1290           ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1291                FIELD_SERVER_DETAILS, le.getMessage()),
1292           le);
1293    }
1294
1295    try
1296    {
1297      final AuthenticationDetails authenticationDetailsSpec =
1298           new AuthenticationDetails(connectionDetailsObject);
1299      bindRequest = authenticationDetailsSpec.getBindRequest();
1300    }
1301    catch (final LDAPException le)
1302    {
1303      Debug.debugException(le);
1304      throw new LDAPException(le.getResultCode(),
1305           ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1306                FIELD_AUTHENTICATION_DETAILS, le.getMessage()),
1307           le);
1308    }
1309
1310    try
1311    {
1312      connectionPoolOptionsSpec =
1313           new ConnectionPoolOptions(connectionDetailsObject);
1314    }
1315    catch (final LDAPException le)
1316    {
1317      Debug.debugException(le);
1318      throw new LDAPException(le.getResultCode(),
1319           ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1320                FIELD_CONNECTION_POOL_OPTIONS, le.getMessage()),
1321           le);
1322    }
1323  }
1324
1325
1326
1327  /**
1328   * Creates a new LDAP connection details object from the specification
1329   * contained in the JSON object represented by the given string.
1330   *
1331   * @param  jsonString  The string representation of the JSON object that
1332   *                     contains information that may be used to create LDAP
1333   *                     connections.
1334   *
1335   * @return  The LDAP connection details object parsed from the provided
1336   *          JSON object string.
1337   *
1338   * @throws  JSONException  If the provided string cannot be parsed as a valid
1339   *                         JSON object.
1340   *
1341   * @throws  LDAPException  If the parsed JSON object does not contain a valid
1342   *                         connection details specification.
1343   */
1344  public static LDAPConnectionDetailsJSONSpecification fromString(
1345                     final String jsonString)
1346         throws JSONException, LDAPException
1347  {
1348    return new LDAPConnectionDetailsJSONSpecification(
1349         new JSONObject(jsonString));
1350  }
1351
1352
1353
1354  /**
1355   * Creates a new LDAP connection details object from the specification
1356   * contained in the JSON object read from the indicated file.
1357   *
1358   * @param  path  The path to a file containing a JSON object with information
1359   *               that may be used to create LDAP connections.
1360   *
1361   * @return  The LDAP connection details object parsed from the information in
1362   *          the specified file.
1363   *
1364   * @throws  IOException  If a problem is encountered while reading from the
1365   *                       specified file.
1366   *
1367   * @throws  JSONException  If the contents of the specified file cannot be
1368   *                         parsed as a valid JSON object.
1369   *
1370   * @throws  LDAPException  If the parsed JSON object does not contain a valid
1371   *                         connection details specification.
1372   */
1373  public static LDAPConnectionDetailsJSONSpecification fromFile(
1374                                                            final String path)
1375         throws IOException, JSONException, LDAPException
1376  {
1377    return fromFile(new File(path));
1378  }
1379
1380
1381
1382  /**
1383   * Creates a new LDAP connection details object from the specification
1384   * contained in the JSON object read from the indicated file.
1385   *
1386   * @param  file  The file containing a JSON object with information that may
1387   *               be used to create LDAP connections.
1388   *
1389   * @return  The LDAP connection details object parsed from the information in
1390   *          the specified file.
1391   *
1392   * @throws  IOException  If a problem is encountered while reading from the
1393   *                       specified file.
1394   *
1395   * @throws  JSONException  If the contents of the specified file cannot be
1396   *                         parsed as a valid JSON object.
1397   *
1398   * @throws  LDAPException  If the parsed JSON object does not contain a valid
1399   *                         connection details specification.
1400   */
1401  public static LDAPConnectionDetailsJSONSpecification fromFile(final File file)
1402         throws IOException, JSONException, LDAPException
1403  {
1404    return fromInputStream(new FileInputStream(file));
1405  }
1406
1407
1408
1409  /**
1410   * Creates a new LDAP connection details object from the specification
1411   * contained in the JSON object read from the provided input stream.  The
1412   * entire contents of the stream must be exactly one JSON object.  Because the
1413   * input stream will be fully read, it will always be closed by this method.
1414   *
1415   * @param  inputStream  The input stream from which to read a JSON object with
1416   *                      information that may be used to create LDAP
1417   *                      connections.  The entire contents of the stream must
1418   *                      be exactly one JSON object.  Because the input stream
1419   *                      will be fully read, it will always be closed by this
1420   *                      method.
1421   *
1422   * @return  The LDAP connection details object parsed from the information
1423   *          read from the provided input stream.
1424   *
1425   * @throws  IOException  If a problem is encountered while reading from the
1426   *                       provided input stream.
1427   *
1428   * @throws  JSONException  If the contents of the specified file cannot be
1429   *                         parsed as a valid JSON object.
1430   *
1431   * @throws  LDAPException  If the parsed JSON object does not contain a valid
1432   *                         connection details specification.
1433   */
1434  public static LDAPConnectionDetailsJSONSpecification fromInputStream(
1435                     final InputStream inputStream)
1436         throws IOException, JSONException, LDAPException
1437  {
1438    try
1439    {
1440      final ByteStringBuffer b = new ByteStringBuffer();
1441      final byte[] readBuffer = new byte[8192];
1442      while (true)
1443      {
1444        final int bytesRead = inputStream.read(readBuffer);
1445        if (bytesRead < 0)
1446        {
1447          break;
1448        }
1449        else
1450        {
1451          b.append(readBuffer, 0, bytesRead);
1452        }
1453      }
1454
1455      return new LDAPConnectionDetailsJSONSpecification(
1456           new JSONObject(b.toString()));
1457    }
1458    finally
1459    {
1460      inputStream.close();
1461    }
1462  }
1463
1464
1465
1466  /**
1467   * Retrieves the server set that may be used to create new connections based
1468   * on the JSON specification.
1469   *
1470   * @return  The server set that may be used to create new connections based on
1471   *          the JSON specification.
1472   */
1473  public ServerSet getServerSet()
1474  {
1475    return serverSet;
1476  }
1477
1478
1479
1480  /**
1481   * Retrieves the bind request that may be used to authenticate connections
1482   * created from the JSON specification.
1483   *
1484   * @return  The bind request that may be used to authenticate connections
1485   *          created from the JSON specification, or {@code null} if the
1486   *          connections should be unauthenticated.
1487   */
1488  public BindRequest getBindRequest()
1489  {
1490    return bindRequest;
1491  }
1492
1493
1494
1495  /**
1496   * Creates a new LDAP connection based on the JSON specification.  The
1497   * connection will be authenticated if appropriate.
1498   *
1499   * @return  The LDAP connection that was created.
1500   *
1501   * @throws  LDAPException  If a problem is encountered while trying to
1502   *                         establish or authenticate the connection.
1503   */
1504  public LDAPConnection createConnection()
1505         throws LDAPException
1506  {
1507    final LDAPConnection connection = createUnauthenticatedConnection();
1508
1509    if (bindRequest != null)
1510    {
1511      try
1512      {
1513        connection.bind(bindRequest);
1514      }
1515      catch (final LDAPException le)
1516      {
1517        Debug.debugException(le);
1518        connection.close();
1519        throw le;
1520      }
1521    }
1522
1523    return connection;
1524  }
1525
1526
1527
1528  /**
1529   * Creates a new LDAP connection based on the JSON specification.  No
1530   * authentication will be performed on the connection.
1531   *
1532   * @return  The LDAP connection that was created.
1533   *
1534   * @throws  LDAPException  If a problem is encountered while trying to
1535   *                         establish the connection.
1536   */
1537  public LDAPConnection createUnauthenticatedConnection()
1538         throws LDAPException
1539  {
1540    return serverSet.getConnection();
1541  }
1542
1543
1544
1545  /**
1546   * Creates a new LDAP connection pool based on the JSON specification.  The
1547   * pooled connections will be authenticated if appropriate.
1548   *
1549   * @param  initialConnections  The number of connections that should be
1550   *                             established at the time the pool is created.
1551   * @param  maximumConnections  The maximum number of connections that should
1552   *                             be available in the pool at any time.
1553   *
1554   * @return  The LDAP connection pool that was created.
1555   *
1556   * @throws  LDAPException  If a problem is encountered while attempting to
1557   *                         create the connection pool.
1558   */
1559  public LDAPConnectionPool createConnectionPool(final int initialConnections,
1560                                                 final int maximumConnections)
1561         throws LDAPException
1562  {
1563    final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet,
1564         bindRequest, initialConnections, maximumConnections,
1565         connectionPoolOptionsSpec.getInitialConnectThreads(),
1566         securityOptionsSpec.getPostConnectProcessor(), false,
1567         connectionPoolOptionsSpec.getHealthCheck());
1568
1569    connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool);
1570    return connectionPool;
1571  }
1572
1573
1574
1575  /**
1576   * Creates a new LDAP connection pool based on the JSON specification.  No
1577   * authentication will be used for connections that are part of the pool.
1578   *
1579   * @param  initialConnections  The number of connections that should be
1580   *                             established at the time the pool is created.
1581   * @param  maximumConnections  The maximum number of connections that should
1582   *                             be available in the pool at any time.
1583   *
1584   * @return  The LDAP connection pool that was created.
1585   *
1586   * @throws  LDAPException  If a problem is encountered while attempting to
1587   *                         create the connection pool.
1588   */
1589  public LDAPConnectionPool createUnauthenticatedConnectionPool(
1590                                 final int initialConnections,
1591                                 final int maximumConnections)
1592       throws LDAPException
1593  {
1594    final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet,
1595         null, initialConnections, maximumConnections,
1596         connectionPoolOptionsSpec.getInitialConnectThreads(),
1597         securityOptionsSpec.getPostConnectProcessor(), false,
1598         connectionPoolOptionsSpec.getHealthCheck());
1599
1600    connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool);
1601    return connectionPool;
1602  }
1603
1604
1605
1606  /**
1607   * Validates the top-level fields in the provided JSON object to ensure that
1608   * all required fields are present and no unrecognized fields are present.
1609   *
1610   * @param  o  The JSON object to validate.
1611   *
1612   * @throws  LDAPException  If there is a problem with the set of top-level
1613   *                         fields in the provided JSON object.
1614   */
1615  private static void validateTopLevelFields(final JSONObject o)
1616          throws LDAPException
1617  {
1618    boolean serverDetailsProvided = false;
1619    for (final String s : o.getFields().keySet())
1620    {
1621      if (s.equals(FIELD_SERVER_DETAILS))
1622      {
1623        // This is a required top-level field.
1624        serverDetailsProvided = true;
1625      }
1626      else if (s.equals(FIELD_CONNECTION_OPTIONS) ||
1627           s.equals(FIELD_COMMUNICATION_SECURITY) ||
1628           s.equals(FIELD_AUTHENTICATION_DETAILS) ||
1629           s.equals(FIELD_CONNECTION_POOL_OPTIONS))
1630      {
1631        // These are optional top-level fields.
1632      }
1633      else
1634      {
1635        // This is not a valid top-level field.
1636        throw new LDAPException(ResultCode.PARAM_ERROR,
1637             ERR_LDAP_SPEC_UNRECOGNIZED_TOP_LEVEL_FIELD.get(s));
1638      }
1639    }
1640
1641    if (! serverDetailsProvided)
1642    {
1643      throw new LDAPException(ResultCode.PARAM_ERROR,
1644           ERR_LDAP_SPEC_MISSING_SERVER_DETAILS.get(FIELD_SERVER_DETAILS));
1645    }
1646  }
1647
1648
1649
1650  /**
1651   * Validates that the set of fields contained in the JSON object that is the
1652   * value of the indicated field.
1653   *
1654   * @param  o  The JSON object to validate.
1655   * @param  f  The name of the field whose value is the provided JSON object.
1656   * @param  a  The names of the fields that are allowed to be present.
1657   *
1658   * @throws  LDAPException  If the provided JSON object contains any fields
1659   *                         that are not contained in the allowed set.
1660   */
1661  static void validateAllowedFields(final JSONObject o, final String f,
1662                                    final String... a)
1663         throws LDAPException
1664  {
1665    final HashSet<String> s = new HashSet<>(Arrays.asList(a));
1666    for (final String n : o.getFields().keySet())
1667    {
1668      if (! s.contains(n))
1669      {
1670        throw new LDAPException(ResultCode.PARAM_ERROR,
1671             ERR_LDAP_SPEC_UNRECOGNIZED_FIELD.get(n, f));
1672      }
1673    }
1674  }
1675
1676
1677
1678  /**
1679   * Retrieves the value of the specified JSON object field as a boolean.
1680   *
1681   * @param  o  The object from which to retrieve the boolean value.
1682   * @param  f  The name of the field to retrieve.
1683   * @param  d  The default value to return if the specified field does not
1684   *            exist.
1685   *
1686   * @return  The requested boolean value.
1687   *
1688   * @throws  LDAPException  If the specified field exists but is not a boolean.
1689   */
1690  static boolean getBoolean(final JSONObject o, final String f, final boolean d)
1691         throws LDAPException
1692  {
1693    final JSONValue v = o.getField(f);
1694    if (v == null)
1695    {
1696      return d;
1697    }
1698
1699    if (v instanceof JSONBoolean)
1700    {
1701      return ((JSONBoolean) v).booleanValue();
1702    }
1703    else
1704    {
1705      throw new LDAPException(ResultCode.PARAM_ERROR,
1706           ERR_LDAP_SPEC_VALUE_NOT_BOOLEAN.get(f));
1707    }
1708  }
1709
1710
1711
1712  /**
1713   * Retrieves the value of the specified JSON object field as an integer.
1714   *
1715   * @param  o  The object from which to retrieve the integer value.
1716   * @param  f  The name of the field to retrieve.
1717   * @param  d  The default value to return if the specified field does not
1718   *            exist.
1719   * @param  n  The minimum allowed value for the field, if any.
1720   * @param  x  The maximum allowed value for the field, if any.
1721   *
1722   * @return  The requested integer value.
1723   *
1724   * @throws  LDAPException  If the specified field exists but is not an
1725   *                         integer.
1726   */
1727  static Integer getInt(final JSONObject o, final String f, final Integer d,
1728                        final Integer n, final Integer x)
1729         throws LDAPException
1730  {
1731    final JSONValue v = o.getField(f);
1732    if (v == null)
1733    {
1734      return d;
1735    }
1736
1737    if (v instanceof JSONNumber)
1738    {
1739      try
1740      {
1741        final int i =((JSONNumber) v).getValue().intValueExact();
1742        if ((n != null) && (i < n))
1743        {
1744          throw new LDAPException(ResultCode.PARAM_ERROR,
1745               ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n));
1746        }
1747
1748        if ((x != null) && (i > x))
1749        {
1750          throw new LDAPException(ResultCode.PARAM_ERROR,
1751               ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n));
1752        }
1753
1754        return i;
1755      }
1756      catch (final LDAPException le)
1757      {
1758        Debug.debugException(le);
1759        throw le;
1760      }
1761      catch (final Exception e)
1762      {
1763        Debug.debugException(e);
1764        throw new LDAPException(ResultCode.PARAM_ERROR,
1765             ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e);
1766      }
1767    }
1768    else
1769    {
1770      throw new LDAPException(ResultCode.PARAM_ERROR,
1771           ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f));
1772    }
1773  }
1774
1775
1776
1777  /**
1778   * Retrieves the value of the specified JSON object field as a long.
1779   *
1780   * @param  o  The object from which to retrieve the long value.
1781   * @param  f  The name of the field to retrieve.
1782   * @param  d  The default value to return if the specified field does not
1783   *            exist.
1784   * @param  n  The minimum allowed value for the field, if any.
1785   * @param  x  The maximum allowed value for the field, if any.
1786   *
1787   * @return  The requested long value.
1788   *
1789   * @throws  LDAPException  If the specified field exists but is not a long.
1790   */
1791  static Long getLong(final JSONObject o, final String f, final Long d,
1792                      final Long n, final Long x)
1793         throws LDAPException
1794  {
1795    final JSONValue v = o.getField(f);
1796    if (v == null)
1797    {
1798      return d;
1799    }
1800
1801    if (v instanceof JSONNumber)
1802    {
1803      try
1804      {
1805        final long l =((JSONNumber) v).getValue().longValueExact();
1806        if ((n != null) && (l < n))
1807        {
1808          throw new LDAPException(ResultCode.PARAM_ERROR,
1809               ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n));
1810        }
1811
1812        if ((x != null) && (l > x))
1813        {
1814          throw new LDAPException(ResultCode.PARAM_ERROR,
1815               ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n));
1816        }
1817
1818        return l;
1819      }
1820      catch (final LDAPException le)
1821      {
1822        Debug.debugException(le);
1823        throw le;
1824      }
1825      catch (final Exception e)
1826      {
1827        Debug.debugException(e);
1828        throw new LDAPException(ResultCode.PARAM_ERROR,
1829             ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e);
1830      }
1831    }
1832    else
1833    {
1834      throw new LDAPException(ResultCode.PARAM_ERROR,
1835           ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f));
1836    }
1837  }
1838
1839
1840
1841  /**
1842   * Retrieves the value of the specified JSON object field as an object.
1843   *
1844   * @param  o  The object from which to retrieve the object value.
1845   * @param  f  The name of the field to retrieve.
1846   *
1847   * @return  The requested object value.
1848   *
1849   * @throws  LDAPException  If the specified field exists but is not an object.
1850   */
1851  static JSONObject getObject(final JSONObject o, final String f)
1852         throws LDAPException
1853  {
1854    final JSONValue v = o.getField(f);
1855    if (v == null)
1856    {
1857      return null;
1858    }
1859
1860    if (v instanceof JSONObject)
1861    {
1862      return (JSONObject) v;
1863    }
1864    else
1865    {
1866      throw new LDAPException(ResultCode.PARAM_ERROR,
1867           ERR_LDAP_SPEC_VALUE_NOT_OBJECT.get(f));
1868    }
1869  }
1870
1871
1872
1873  /**
1874   * Retrieves the value of the specified JSON object field as a string.
1875   *
1876   * @param  o  The object from which to retrieve the string value.
1877   * @param  f  The name of the field to retrieve.
1878   * @param  d  The default value to return if the specified field does not
1879   *            exist.
1880   *
1881   * @return  The requested string value.
1882   *
1883   * @throws  LDAPException  If the specified field exists but is not a string.
1884   */
1885  static String getString(final JSONObject o, final String f, final String d)
1886         throws LDAPException
1887  {
1888    final JSONValue v = o.getField(f);
1889    if (v == null)
1890    {
1891      return d;
1892    }
1893
1894    if (v instanceof JSONString)
1895    {
1896      return ((JSONString) v).stringValue();
1897    }
1898    else
1899    {
1900      throw new LDAPException(ResultCode.PARAM_ERROR,
1901           ERR_LDAP_SPEC_VALUE_NOT_STRING.get(f));
1902    }
1903  }
1904
1905
1906
1907  /**
1908   * Retrieves a string value read from the specified file.  The file must
1909   * contain exactly one line, and that line must not be empty.
1910   *
1911   * @param  path       The path to the file from which to read the string.
1912   * @param  fieldName  The name of the field from which the path was obtained.
1913   *
1914   * @return  The string read from the specified file.
1915   *
1916   * @throws  LDAPException  If a problem is encountered while reading from the
1917   *                         specified file, if the file does not contain
1918   *                         exactly one line, or if the line contained in the
1919   *                         file is empty.
1920   */
1921  static String getStringFromFile(final String path, final String fieldName)
1922         throws LDAPException
1923  {
1924    BufferedReader r = null;
1925    try
1926    {
1927      r = new BufferedReader(new FileReader(path));
1928
1929      final String line = r.readLine();
1930      if (line == null)
1931      {
1932        throw new LDAPException(ResultCode.PARAM_ERROR,
1933             ERR_LDAP_SPEC_READ_FILE_EMPTY.get(path, fieldName));
1934      }
1935
1936      if (r.readLine() != null)
1937      {
1938        throw new LDAPException(ResultCode.PARAM_ERROR,
1939             ERR_LDAP_SPEC_READ_FILE_MULTIPLE_LINES.get(path, fieldName));
1940      }
1941
1942      if (line.isEmpty())
1943      {
1944        throw new LDAPException(ResultCode.PARAM_ERROR,
1945             ERR_LDAP_SPEC_READ_FILE_EMPTY_LINE.get(path, fieldName));
1946      }
1947
1948      return line;
1949    }
1950    catch (final LDAPException le)
1951    {
1952      Debug.debugException(le);
1953      throw le;
1954    }
1955    catch (final Exception e)
1956    {
1957      Debug.debugException(e);
1958      throw new LDAPException(ResultCode.PARAM_ERROR,
1959           ERR_LDAP_SPEC_READ_FILE_ERROR.get(path, fieldName,
1960                StaticUtils.getExceptionMessage(e)),
1961           e);
1962    }
1963    finally
1964    {
1965      if (r != null)
1966      {
1967        try
1968        {
1969          r.close();
1970        }
1971        catch (final Exception e)
1972        {
1973          Debug.debugException(e);
1974        }
1975      }
1976    }
1977  }
1978
1979
1980
1981  /**
1982   * Verifies that none of the indicated fields exist in the provided JSON
1983   * object because they would conflict with the specified existing field.
1984   *
1985   * @param  o                  The JSON object to examine.
1986   * @param  existingField      The name of a field known to be present in the
1987   *                            JSON object that cannot coexist with the
1988   *                            indicated conflicting fields.
1989   * @param  conflictingFields  The names of the fields that cannot be used in
1990   *                            conjunction with the specified existing field.
1991   *
1992   * @throws  LDAPException  If the provided JSON object has one or more fields
1993   *                         that conflict with the specified existing field.
1994   */
1995  static void rejectConflictingFields(final JSONObject o,
1996                                      final String existingField,
1997                                      final String... conflictingFields)
1998         throws LDAPException
1999  {
2000    for (final String fieldName : conflictingFields)
2001    {
2002      if (o.getField(fieldName) != null)
2003      {
2004        throw new LDAPException(ResultCode.PARAM_ERROR,
2005             ERR_LDAP_SPEC_CONFLICTING_FIELD.get(fieldName, existingField));
2006      }
2007    }
2008  }
2009
2010
2011
2012  /**
2013   * Verifies that none of the indicated fields exist in the provided JSON
2014   * object because they can only be provided if the specified required field is
2015   * present.
2016   *
2017   * @param  o                The JSON object to examine.
2018   * @param  requiredField    The name of a field known to be missing from the
2019   *                          JSON object, but must be present to allow any of
2020   *                          the indicated dependent fields to be provided.
2021   * @param  dependentFields  The names of the fields that can only be present
2022   *                          if the specified required field is present.
2023   *
2024   * @throws  LDAPException  If the provided JSON object has one or more
2025   *                         unresolved dependencies.
2026   */
2027  static void rejectUnresolvedDependency(final JSONObject o,
2028                                         final String requiredField,
2029                                         final String... dependentFields)
2030         throws LDAPException
2031  {
2032    for (final String fieldName : dependentFields)
2033    {
2034      if (o.getField(fieldName) != null)
2035      {
2036        throw new LDAPException(ResultCode.PARAM_ERROR,
2037             ERR_LDAP_SPEC_MISSING_DEPENDENT_FIELD.get(fieldName,
2038                  requiredField));
2039      }
2040    }
2041  }
2042}