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