001/* 002 * Copyright 2011-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2022 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) 2011-2022 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.ldap.listener; 037 038 039 040import java.io.File; 041import java.io.IOException; 042import java.net.InetAddress; 043import java.util.ArrayList; 044import java.util.Arrays; 045import java.util.Collection; 046import java.util.Collections; 047import java.util.LinkedHashMap; 048import java.util.List; 049import java.util.Map; 050import javax.net.SocketFactory; 051 052import com.unboundid.asn1.ASN1OctetString; 053import com.unboundid.ldap.listener.interceptor. 054 InMemoryOperationInterceptorRequestHandler; 055import com.unboundid.ldap.protocol.BindRequestProtocolOp; 056import com.unboundid.ldap.protocol.BindResponseProtocolOp; 057import com.unboundid.ldap.protocol.CompareRequestProtocolOp; 058import com.unboundid.ldap.protocol.CompareResponseProtocolOp; 059import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp; 060import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp; 061import com.unboundid.ldap.protocol.LDAPMessage; 062import com.unboundid.ldap.protocol.SearchRequestProtocolOp; 063import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp; 064import com.unboundid.ldap.sdk.AddRequest; 065import com.unboundid.ldap.sdk.Attribute; 066import com.unboundid.ldap.sdk.BindRequest; 067import com.unboundid.ldap.sdk.BindResult; 068import com.unboundid.ldap.sdk.CompareRequest; 069import com.unboundid.ldap.sdk.CompareResult; 070import com.unboundid.ldap.sdk.Control; 071import com.unboundid.ldap.sdk.DeleteRequest; 072import com.unboundid.ldap.sdk.DereferencePolicy; 073import com.unboundid.ldap.sdk.DN; 074import com.unboundid.ldap.sdk.Entry; 075import com.unboundid.ldap.sdk.ExtendedRequest; 076import com.unboundid.ldap.sdk.ExtendedResult; 077import com.unboundid.ldap.sdk.Filter; 078import com.unboundid.ldap.sdk.FullLDAPInterface; 079import com.unboundid.ldap.sdk.InternalSDKHelper; 080import com.unboundid.ldap.sdk.LDAPConnection; 081import com.unboundid.ldap.sdk.LDAPConnectionOptions; 082import com.unboundid.ldap.sdk.LDAPConnectionPool; 083import com.unboundid.ldap.sdk.LDAPException; 084import com.unboundid.ldap.sdk.LDAPResult; 085import com.unboundid.ldap.sdk.LDAPSearchException; 086import com.unboundid.ldap.sdk.Modification; 087import com.unboundid.ldap.sdk.ModifyRequest; 088import com.unboundid.ldap.sdk.ModifyDNRequest; 089import com.unboundid.ldap.sdk.PLAINBindRequest; 090import com.unboundid.ldap.sdk.ReadOnlyAddRequest; 091import com.unboundid.ldap.sdk.ReadOnlyCompareRequest; 092import com.unboundid.ldap.sdk.ReadOnlyDeleteRequest; 093import com.unboundid.ldap.sdk.ReadOnlyModifyRequest; 094import com.unboundid.ldap.sdk.ReadOnlyModifyDNRequest; 095import com.unboundid.ldap.sdk.ReadOnlySearchRequest; 096import com.unboundid.ldap.sdk.ResultCode; 097import com.unboundid.ldap.sdk.RootDSE; 098import com.unboundid.ldap.sdk.SearchRequest; 099import com.unboundid.ldap.sdk.SearchResult; 100import com.unboundid.ldap.sdk.SearchResultEntry; 101import com.unboundid.ldap.sdk.SearchResultListener; 102import com.unboundid.ldap.sdk.SearchResultReference; 103import com.unboundid.ldap.sdk.SearchScope; 104import com.unboundid.ldap.sdk.SimpleBindRequest; 105import com.unboundid.ldap.sdk.schema.Schema; 106import com.unboundid.ldif.LDIFException; 107import com.unboundid.ldif.LDIFReader; 108import com.unboundid.ldif.LDIFWriter; 109import com.unboundid.util.ByteStringBuffer; 110import com.unboundid.util.Debug; 111import com.unboundid.util.Mutable; 112import com.unboundid.util.NotNull; 113import com.unboundid.util.Nullable; 114import com.unboundid.util.StaticUtils; 115import com.unboundid.util.ThreadSafety; 116import com.unboundid.util.ThreadSafetyLevel; 117import com.unboundid.util.Validator; 118 119import static com.unboundid.ldap.listener.ListenerMessages.*; 120 121 122 123/** 124 * This class provides a utility that may be used to create a simple LDAP server 125 * instance that will hold all of its information in memory. It is intended to 126 * be very easy to use, particularly as an embeddable server for testing 127 * directory-enabled applications. It can be easily created, configured, 128 * populated, and shut down with only a few lines of code, and it provides a 129 * number of convenience methods that can be very helpful in writing test cases 130 * that validate the content of the server. 131 * <BR><BR> 132 * Some notes about the capabilities of this server: 133 * <UL> 134 * <LI>It provides reasonably complete support for add, compare, delete, 135 * modify, modify DN (including new superior and subtree move/rename), 136 * search, and unbind operations.</LI> 137 * <LI>It will accept abandon requests, but will not do anything with 138 * them.</LI> 139 * <LI>It provides support for simple bind operations, and for the SASL PLAIN 140 * mechanism. It also provides an API that can be used to add support for 141 * additional SASL mechanisms.</LI> 142 * <LI>It provides support for the password modify, StartTLS, and "who am I?" 143 * extended operations, as well as an API that can be used to add support 144 * for additional types of extended operations.</LI> 145 * <LI>It provides support for the LDAP assertions, authorization identity, 146 * don't use copy, manage DSA IT, permissive modify, pre-read, post-read, 147 * proxied authorization v1 and v2, server-side sort, simple paged 148 * results, LDAP subentries, subtree delete, and virtual list view request 149 * controls.</LI> 150 * <LI>It supports the use of schema (if provided), but it does not currently 151 * allow updating the schema on the fly.</LI> 152 * <LI>It has the ability to maintain a log of operations processed, as a 153 * simple access log, a more detailed LDAP debug log, or even a log with 154 * generated code that may be used to construct and issue the requests 155 * received by clients.</LI> 156 * <LI>It has the ability to maintain an LDAP-accessible changelog.</LI> 157 * <LI>It provides an option to generate a number of operational attributes, 158 * including entryDN, entryUUID, creatorsName, createTimestamp, 159 * modifiersName, modifyTimestamp, and subschemaSubentry.</LI> 160 * <LI>It provides support for referential integrity, in which case specified 161 * attributes whose values are DNs may be updated if the entries they 162 * reference are deleted or renamed.</LI> 163 * <LI>It provides methods for importing data from and exporting data to LDIF 164 * files, and it has the ability to capture a point-in-time snapshot of 165 * the data (including changelog information) that may be restored at any 166 * point.</LI> 167 * <LI>It implements the {@link FullLDAPInterface} interface, which means that 168 * in many cases it can be used as a drop-in replacement for an 169 * {@link LDAPConnection}.</LI> 170 * </UL> 171 * <BR><BR> 172 * In order to create an in-memory directory server instance, you should first 173 * create an {@link InMemoryDirectoryServerConfig} object with the desired 174 * settings. Then use that configuration object to initialize the directory 175 * server instance, and call the {@link #startListening} method to start 176 * accepting connections from LDAP clients. The {@link #getConnection} and 177 * {@link #getConnectionPool} methods may be used to obtain connections to the 178 * server and you can also manually create connections using the information 179 * obtained via the {@link #getListenAddress}, {@link #getListenPort}, and 180 * {@link #getClientSocketFactory} methods. When the server is no longer 181 * needed, the {@link #shutDown} method should be used to stop the server. Any 182 * number of in-memory directory server instances can be created and running in 183 * a single JVM at any time, and many of the methods provided in this class can 184 * be used without the server running if operations are to be performed using 185 * only method calls rather than via LDAP clients. 186 * <BR><BR> 187 * <H2>Example</H2> 188 * The following example demonstrates the process that can be used to create, 189 * start, and use an in-memory directory server instance, including support for 190 * secure communication using both SSL and StartTLS: 191 * <PRE> 192 * // Create a base configuration for the server. 193 * InMemoryDirectoryServerConfig config = 194 * new InMemoryDirectoryServerConfig("dc=example,dc=com"); 195 * config.addAdditionalBindCredentials("cn=Directory Manager", 196 * "password"); 197 * 198 * // Update the configuration to support LDAP (with StartTLS) and LDAPS 199 * // listeners. 200 * final SSLUtil serverSSLUtil = new SSLUtil( 201 * new KeyStoreKeyManager(serverKeyStorePath, serverKeyStorePIN, "JKS", 202 * "server-cert"), 203 * new TrustStoreTrustManager(serverTrustStorePath)); 204 * final SSLUtil clientSSLUtil = new SSLUtil( 205 * new TrustStoreTrustManager(clientTrustStorePath)); 206 * config.setListenerConfigs( 207 * InMemoryListenerConfig.createLDAPConfig("LDAP", // Listener name 208 * null, // Listen address. (null = listen on all interfaces) 209 * 0, // Listen port (0 = automatically choose an available port) 210 * serverSSLUtil.createSSLSocketFactory()), // StartTLS factory 211 * InMemoryListenerConfig.createLDAPSConfig("LDAPS", // Listener name 212 * null, // Listen address. (null = listen on all interfaces) 213 * 0, // Listen port (0 = automatically choose an available port) 214 * serverSSLUtil.createSSLServerSocketFactory(), // Server factory 215 * clientSSLUtil.createSSLSocketFactory())); // Client factory 216 * 217 * // Create and start the server instance and populate it with an initial set 218 * // of data from an LDIF file. 219 * InMemoryDirectoryServer server = new InMemoryDirectoryServer(config); 220 * server.importFromLDIF(true, ldifFilePath); 221 * 222 * // Start the server so it will accept client connections. 223 * server.startListening(); 224 * 225 * // Get an unencrypted connection to the server's LDAP listener, then use 226 * // StartTLS to secure that connection. Make sure the connection is usable 227 * // by retrieving the server root DSE. 228 * LDAPConnection connection = server.getConnection("LDAP"); 229 * connection.processExtendedOperation(new StartTLSExtendedRequest( 230 * clientSSLUtil.createSSLContext())); 231 * LDAPTestUtils.assertEntryExists(connection, ""); 232 * connection.close(); 233 * 234 * // Establish an SSL-based connection to the LDAPS listener, and make sure 235 * // that connection is also usable. 236 * connection = server.getConnection("LDAPS"); 237 * LDAPTestUtils.assertEntryExists(connection, ""); 238 * connection.close(); 239 * 240 * // Shut down the server so that it will no longer accept client 241 * // connections, and close all existing connections. 242 * server.shutDown(true); 243 * </PRE> 244 */ 245@Mutable() 246@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 247public final class InMemoryDirectoryServer 248 implements FullLDAPInterface 249{ 250 // The in-memory request handler that will be used for the server. 251 @NotNull private final InMemoryRequestHandler inMemoryHandler; 252 253 // The set of listeners that have been configured for this server, mapped by 254 // listener name. 255 @NotNull private final Map<String,LDAPListener> listeners; 256 257 // The set of configurations for all the LDAP listeners to be used. 258 @NotNull private final Map<String,LDAPListenerConfig> ldapListenerConfigs; 259 260 // The set of client socket factories associated with each of the listeners. 261 @NotNull private final Map<String,SocketFactory> clientSocketFactories; 262 263 // A read-only representation of the configuration used to create this 264 // in-memory directory server. 265 @NotNull private final ReadOnlyInMemoryDirectoryServerConfig config; 266 267 268 269 /** 270 * Creates a very simple instance of an in-memory directory server with the 271 * specified set of base DNs. It will not use a well-defined schema, and will 272 * pick a listen port at random. 273 * 274 * @param baseDNs The base DNs to use for the server. It must not be 275 * {@code null} or empty. 276 * 277 * @throws LDAPException If a problem occurs while attempting to initialize 278 * the server. 279 */ 280 public InMemoryDirectoryServer(@NotNull final String... baseDNs) 281 throws LDAPException 282 { 283 this(new InMemoryDirectoryServerConfig(baseDNs)); 284 } 285 286 287 288 /** 289 * Creates a new instance of an in-memory directory server with the provided 290 * configuration. 291 * 292 * @param cfg The configuration to use for the server. It must not be 293 * {@code null}. 294 * 295 * @throws LDAPException If a problem occurs while trying to initialize the 296 * directory server with the provided configuration. 297 */ 298 public InMemoryDirectoryServer( 299 @NotNull final InMemoryDirectoryServerConfig cfg) 300 throws LDAPException 301 { 302 Validator.ensureNotNull(cfg); 303 304 config = new ReadOnlyInMemoryDirectoryServerConfig(cfg); 305 inMemoryHandler = new InMemoryRequestHandler(config); 306 307 LDAPListenerRequestHandler requestHandler = inMemoryHandler; 308 309 if (config.getAccessLogHandler() != null) 310 { 311 requestHandler = new AccessLogRequestHandler(config.getAccessLogHandler(), 312 requestHandler); 313 } 314 315 if (config.getJSONAccessLogHandler() != null) 316 { 317 requestHandler = new JSONAccessLogRequestHandler( 318 config.getJSONAccessLogHandler(), requestHandler); 319 } 320 321 if (config.getLDAPDebugLogHandler() != null) 322 { 323 requestHandler = new LDAPDebuggerRequestHandler( 324 config.getLDAPDebugLogHandler(), requestHandler); 325 } 326 327 if (config.getCodeLogPath() != null) 328 { 329 try 330 { 331 requestHandler = new ToCodeRequestHandler(config.getCodeLogPath(), 332 config.includeRequestProcessingInCodeLog(), requestHandler); 333 } 334 catch (final IOException ioe) 335 { 336 Debug.debugException(ioe); 337 throw new LDAPException(ResultCode.LOCAL_ERROR, 338 ERR_MEM_DS_CANNOT_OPEN_CODE_LOG.get(config.getCodeLogPath(), 339 StaticUtils.getExceptionMessage(ioe)), 340 ioe); 341 } 342 } 343 344 if (! config.getOperationInterceptors().isEmpty()) 345 { 346 requestHandler = new InMemoryOperationInterceptorRequestHandler( 347 config.getOperationInterceptors(), requestHandler); 348 } 349 350 351 final List<InMemoryListenerConfig> listenerConfigs = 352 config.getListenerConfigs(); 353 354 listeners = new LinkedHashMap<>( 355 StaticUtils.computeMapCapacity(listenerConfigs.size())); 356 ldapListenerConfigs = new LinkedHashMap<>( 357 StaticUtils.computeMapCapacity(listenerConfigs.size())); 358 clientSocketFactories = new LinkedHashMap<>( 359 StaticUtils.computeMapCapacity(listenerConfigs.size())); 360 361 for (final InMemoryListenerConfig c : listenerConfigs) 362 { 363 final String name = StaticUtils.toLowerCase(c.getListenerName()); 364 365 final LDAPListenerRequestHandler listenerRequestHandler; 366 if (c.getStartTLSSocketFactory() == null) 367 { 368 listenerRequestHandler = requestHandler; 369 } 370 else 371 { 372 listenerRequestHandler = 373 new StartTLSRequestHandler(c.getStartTLSSocketFactory(), 374 requestHandler, c.requestClientCertificate(), 375 c.requireClientCertificate()); 376 } 377 378 final LDAPListenerConfig listenerCfg = new LDAPListenerConfig( 379 c.getListenPort(), listenerRequestHandler); 380 listenerCfg.setMaxConnections(config.getMaxConnections()); 381 listenerCfg.setMaxMessageSizeBytes(config.getMaxMessageSizeBytes()); 382 listenerCfg.setExceptionHandler(config.getListenerExceptionHandler()); 383 listenerCfg.setListenAddress(c.getListenAddress()); 384 listenerCfg.setServerSocketFactory(c.getServerSocketFactory()); 385 listenerCfg.setRequestClientCertificate(c.requestClientCertificate()); 386 listenerCfg.setRequireClientCertificate(c.requireClientCertificate()); 387 388 ldapListenerConfigs.put(name, listenerCfg); 389 390 if (c.getClientSocketFactory() != null) 391 { 392 clientSocketFactories.put(name, c.getClientSocketFactory()); 393 } 394 } 395 } 396 397 398 399 /** 400 * Attempts to start listening for client connections on all configured 401 * listeners. Any listeners that are already running will be unaffected. 402 * 403 * @throws LDAPException If a problem occurs while attempting to create any 404 * of the configured listeners. Even if an exception 405 * is thrown, then as many listeners as possible will 406 * be started. 407 */ 408 public synchronized void startListening() 409 throws LDAPException 410 { 411 final ArrayList<String> messages = new ArrayList<>(listeners.size()); 412 413 for (final Map.Entry<String,LDAPListenerConfig> cfgEntry : 414 ldapListenerConfigs.entrySet()) 415 { 416 final String name = cfgEntry.getKey(); 417 418 if (listeners.containsKey(name)) 419 { 420 // This listener is already running. 421 continue; 422 } 423 424 final LDAPListenerConfig listenerConfig = cfgEntry.getValue(); 425 final LDAPListener listener = new LDAPListener(listenerConfig); 426 427 try 428 { 429 listener.startListening(); 430 listenerConfig.setListenPort(listener.getListenPort()); 431 listeners.put(name, listener); 432 } 433 catch (final Exception e) 434 { 435 Debug.debugException(e); 436 messages.add(ERR_MEM_DS_START_FAILED.get(name, 437 StaticUtils.getExceptionMessage(e))); 438 } 439 } 440 441 if (! messages.isEmpty()) 442 { 443 throw new LDAPException(ResultCode.LOCAL_ERROR, 444 StaticUtils.concatenateStrings(messages)); 445 } 446 } 447 448 449 450 /** 451 * Attempts to start listening for client connections on the specified 452 * listener. If the listener is already running, then it will be unaffected. 453 * 454 * @param listenerName The name of the listener to be started. It must not 455 * be {@code null}. 456 * 457 * @throws LDAPException If a problem occurs while attempting to start the 458 * requested listener. 459 */ 460 public synchronized void startListening(@NotNull final String listenerName) 461 throws LDAPException 462 { 463 // If the listener is already running, then there's nothing to do. 464 final String name = StaticUtils .toLowerCase(listenerName); 465 if (listeners.containsKey(name)) 466 { 467 return; 468 } 469 470 // Get the configuration to use for the listener. 471 final LDAPListenerConfig listenerConfig = ldapListenerConfigs.get(name); 472 if (listenerConfig == null) 473 { 474 throw new LDAPException(ResultCode.PARAM_ERROR, 475 ERR_MEM_DS_NO_SUCH_LISTENER.get(listenerName)); 476 } 477 478 479 final LDAPListener listener = new LDAPListener(listenerConfig); 480 481 try 482 { 483 listener.startListening(); 484 listenerConfig.setListenPort(listener.getListenPort()); 485 listeners.put(name, listener); 486 } 487 catch (final Exception e) 488 { 489 Debug.debugException(e); 490 throw new LDAPException(ResultCode.LOCAL_ERROR, 491 ERR_MEM_DS_START_FAILED.get(name, 492 StaticUtils.getExceptionMessage(e)), 493 e); 494 } 495 } 496 497 498 499 /** 500 * {@inheritDoc} 501 */ 502 @Override() 503 public void close() 504 { 505 shutDown(true); 506 } 507 508 509 510 /** 511 * Closes all connections that are currently established to the server. This 512 * has no effect on the ability to accept new connections. 513 * 514 * @param sendNoticeOfDisconnection Indicates whether to send the client a 515 * notice of disconnection unsolicited 516 * notification before closing the 517 * connection. 518 */ 519 public synchronized void closeAllConnections( 520 final boolean sendNoticeOfDisconnection) 521 { 522 for (final LDAPListener l : listeners.values()) 523 { 524 try 525 { 526 l.closeAllConnections(sendNoticeOfDisconnection); 527 } 528 catch (final Exception e) 529 { 530 Debug.debugException(e); 531 } 532 } 533 } 534 535 536 537 /** 538 * Shuts down all configured listeners. Any listeners that are already 539 * stopped will be unaffected. 540 * 541 * @param closeExistingConnections Indicates whether to close all existing 542 * connections, or merely to stop accepting 543 * new connections. 544 */ 545 public synchronized void shutDown(final boolean closeExistingConnections) 546 { 547 for (final LDAPListener l : listeners.values()) 548 { 549 try 550 { 551 l.shutDown(closeExistingConnections); 552 } 553 catch (final Exception e) 554 { 555 Debug.debugException(e); 556 } 557 } 558 559 listeners.clear(); 560 } 561 562 563 564 /** 565 * Shuts down the specified listener. If there is no such listener defined, 566 * or if the specified listener is not running, then no action will be taken. 567 * 568 * @param listenerName The name of the listener to be shut down. 569 * It must not be {@code null}. 570 * @param closeExistingConnections Indicates whether to close all existing 571 * connections, or merely to stop accepting 572 * new connections. 573 */ 574 public synchronized void shutDown(@NotNull final String listenerName, 575 final boolean closeExistingConnections) 576 { 577 final String name = StaticUtils.toLowerCase(listenerName); 578 final LDAPListener listener = listeners.remove(name); 579 if (listener != null) 580 { 581 listener.shutDown(closeExistingConnections); 582 } 583 } 584 585 586 587 /** 588 * Attempts to restart all listeners defined in the server. All running 589 * listeners will be stopped, and all configured listeners will be started. 590 * 591 * @throws LDAPException If a problem occurs while attempting to restart any 592 * of the listeners. Even if an exception is thrown, 593 * as many listeners as possible will be started. 594 */ 595 public synchronized void restartServer() 596 throws LDAPException 597 { 598 shutDown(true); 599 600 try 601 { 602 Thread.sleep(100L); 603 } 604 catch (final Exception e) 605 { 606 Debug.debugException(e); 607 608 if (e instanceof InterruptedException) 609 { 610 Thread.currentThread().interrupt(); 611 } 612 } 613 614 startListening(); 615 } 616 617 618 619 /** 620 * Attempts to restart the specified listener. If it is running, it will be 621 * stopped. It will then be started. 622 * 623 * @param listenerName The name of the listener to be restarted. It must 624 * not be {@code null}. 625 * 626 * @throws LDAPException If a problem occurs while attempting to restart the 627 * specified listener. 628 */ 629 public synchronized void restartListener(@NotNull final String listenerName) 630 throws LDAPException 631 { 632 shutDown(listenerName, true); 633 634 try 635 { 636 Thread.sleep(100L); 637 } 638 catch (final Exception e) 639 { 640 Debug.debugException(e); 641 642 if (e instanceof InterruptedException) 643 { 644 Thread.currentThread().interrupt(); 645 } 646 } 647 648 startListening(listenerName); 649 } 650 651 652 653 /** 654 * Retrieves a read-only representation of the configuration used to create 655 * this in-memory directory server instance. 656 * 657 * @return A read-only representation of the configuration used to create 658 * this in-memory directory server instance. 659 */ 660 @NotNull() 661 public ReadOnlyInMemoryDirectoryServerConfig getConfig() 662 { 663 return config; 664 } 665 666 667 668 /** 669 * Retrieves the in-memory request handler that is used to perform the real 670 * server processing. 671 * 672 * @return The in-memory request handler that is used to perform the real 673 * server processing. 674 */ 675 @NotNull() 676 InMemoryRequestHandler getInMemoryRequestHandler() 677 { 678 return inMemoryHandler; 679 } 680 681 682 683 /** 684 * Creates a point-in-time snapshot of the information contained in this 685 * in-memory directory server instance. It may be restored using the 686 * {@link #restoreSnapshot} method. 687 * <BR><BR> 688 * This method may be used regardless of whether the server is listening for 689 * client connections. 690 * 691 * @return The snapshot created based on the current content of this 692 * in-memory directory server instance. 693 */ 694 @NotNull() 695 public InMemoryDirectoryServerSnapshot createSnapshot() 696 { 697 return inMemoryHandler.createSnapshot(); 698 } 699 700 701 702 /** 703 * Restores the this in-memory directory server instance to match the content 704 * it held at the time the snapshot was created. 705 * <BR><BR> 706 * This method may be used regardless of whether the server is listening for 707 * client connections. 708 * 709 * @param snapshot The snapshot to be restored. It must not be 710 * {@code null}. 711 */ 712 public void restoreSnapshot( 713 @NotNull final InMemoryDirectoryServerSnapshot snapshot) 714 { 715 inMemoryHandler.restoreSnapshot(snapshot); 716 } 717 718 719 720 /** 721 * Retrieves the list of base DNs configured for use by the server. 722 * 723 * @return The list of base DNs configured for use by the server. 724 */ 725 @NotNull() 726 public List<DN> getBaseDNs() 727 { 728 return inMemoryHandler.getBaseDNs(); 729 } 730 731 732 733 /** 734 * Attempts to establish a client connection to the server. If multiple 735 * listeners are configured, then it will attempt to establish a connection to 736 * the first configured listener that is running. 737 * 738 * @return The client connection that has been established. 739 * 740 * @throws LDAPException If a problem is encountered while attempting to 741 * create the connection. 742 */ 743 @NotNull() 744 public LDAPConnection getConnection() 745 throws LDAPException 746 { 747 return getConnection(null, null); 748 } 749 750 751 752 /** 753 * Attempts to establish a client connection to the server. 754 * 755 * @param options The connection options to use when creating the 756 * connection. It may be {@code null} if a default set of 757 * options should be used. 758 * 759 * @return The client connection that has been established. 760 * 761 * @throws LDAPException If a problem is encountered while attempting to 762 * create the connection. 763 */ 764 @NotNull() 765 public LDAPConnection getConnection( 766 @Nullable final LDAPConnectionOptions options) 767 throws LDAPException 768 { 769 return getConnection(null, options); 770 } 771 772 773 774 /** 775 * Attempts to establish a client connection to the specified listener. 776 * 777 * @param listenerName The name of the listener to which to establish the 778 * connection. It may be {@code null} if a connection 779 * should be established to the first available 780 * listener. 781 * 782 * @return The client connection that has been established. 783 * 784 * @throws LDAPException If a problem is encountered while attempting to 785 * create the connection. 786 */ 787 @NotNull() 788 public LDAPConnection getConnection(@Nullable final String listenerName) 789 throws LDAPException 790 { 791 return getConnection(listenerName, null); 792 } 793 794 795 796 /** 797 * Attempts to establish a client connection to the specified listener. 798 * 799 * @param listenerName The name of the listener to which to establish the 800 * connection. It may be {@code null} if a connection 801 * should be established to the first available 802 * listener. 803 * @param options The set of LDAP connection options to use for the 804 * connection that is created. 805 * 806 * @return The client connection that has been established. 807 * 808 * @throws LDAPException If a problem is encountered while attempting to 809 * create the connection. 810 */ 811 @NotNull() 812 public synchronized LDAPConnection getConnection( 813 @Nullable final String listenerName, 814 @Nullable final LDAPConnectionOptions options) 815 throws LDAPException 816 { 817 final LDAPListenerConfig listenerConfig; 818 final SocketFactory clientSocketFactory; 819 820 if (listenerName == null) 821 { 822 final String name = getFirstListenerName(); 823 if (name == null) 824 { 825 throw new LDAPException(ResultCode.CONNECT_ERROR, 826 ERR_MEM_DS_GET_CONNECTION_NO_LISTENERS.get()); 827 } 828 829 listenerConfig = ldapListenerConfigs.get(name); 830 clientSocketFactory = clientSocketFactories.get(name); 831 } 832 else 833 { 834 final String name = StaticUtils.toLowerCase(listenerName); 835 if (! listeners.containsKey(name)) 836 { 837 throw new LDAPException(ResultCode.CONNECT_ERROR, 838 ERR_MEM_DS_GET_CONNECTION_LISTENER_NOT_RUNNING.get(listenerName)); 839 } 840 841 listenerConfig = ldapListenerConfigs.get(name); 842 clientSocketFactory = clientSocketFactories.get(name); 843 } 844 845 String hostAddress; 846 final InetAddress listenAddress = listenerConfig.getListenAddress(); 847 if ((listenAddress == null) || (listenAddress.isAnyLocalAddress())) 848 { 849 try 850 { 851 hostAddress = LDAPConnectionOptions.DEFAULT_NAME_RESOLVER. 852 getLocalHost().getHostAddress(); 853 } 854 catch (final Exception e) 855 { 856 Debug.debugException(e); 857 hostAddress = "127.0.0.1"; 858 } 859 } 860 else 861 { 862 hostAddress = listenAddress.getHostAddress(); 863 } 864 865 return new LDAPConnection(clientSocketFactory, options, hostAddress, 866 listenerConfig.getListenPort()); 867 } 868 869 870 871 /** 872 * Attempts to establish a connection pool to the server with the specified 873 * maximum number of connections. 874 * 875 * @param maxConnections The maximum number of connections to maintain in 876 * the connection pool. It must be greater than or 877 * equal to one. 878 * 879 * @return The connection pool that has been created. 880 * 881 * @throws LDAPException If a problem occurs while attempting to create the 882 * connection pool. 883 */ 884 @NotNull() 885 public LDAPConnectionPool getConnectionPool(final int maxConnections) 886 throws LDAPException 887 { 888 return getConnectionPool(null, null, 1, maxConnections); 889 } 890 891 892 893 /** 894 * Attempts to establish a connection pool to the server with the provided 895 * settings. 896 * 897 * @param listenerName The name of the listener to which the 898 * connections should be established. 899 * @param options The connection options to use when creating 900 * connections for use in the pool. It may be 901 * {@code null} if a default set of options should 902 * be used. 903 * @param initialConnections The initial number of connections to establish 904 * in the connection pool. It must be greater 905 * than or equal to one. 906 * @param maxConnections The maximum number of connections to maintain 907 * in the connection pool. It must be greater 908 * than or equal to the initial number of 909 * connections. 910 * 911 * @return The connection pool that has been created. 912 * 913 * @throws LDAPException If a problem occurs while attempting to create the 914 * connection pool. 915 */ 916 @NotNull() 917 public LDAPConnectionPool getConnectionPool( 918 @Nullable final String listenerName, 919 @Nullable final LDAPConnectionOptions options, 920 final int initialConnections, 921 final int maxConnections) 922 throws LDAPException 923 { 924 final LDAPConnection conn = getConnection(listenerName, options); 925 return new LDAPConnectionPool(conn, initialConnections, maxConnections); 926 } 927 928 929 930 /** 931 * Retrieves the configured listen address for the first active listener, if 932 * defined. 933 * 934 * @return The configured listen address for the first active listener, or 935 * {@code null} if that listener does not have an 936 * explicitly-configured listen address or there are no active 937 * listeners. 938 */ 939 @Nullable() 940 public InetAddress getListenAddress() 941 { 942 return getListenAddress(null); 943 } 944 945 946 947 /** 948 * Retrieves the configured listen address for the specified listener, if 949 * defined. 950 * 951 * @param listenerName The name of the listener for which to retrieve the 952 * listen address. It may be {@code null} in order to 953 * obtain the listen address for the first active 954 * listener. 955 * 956 * @return The configured listen address for the specified listener, or 957 * {@code null} if there is no such listener or the listener does not 958 * have an explicitly-configured listen address. 959 */ 960 @Nullable() 961 public synchronized InetAddress getListenAddress( 962 @Nullable final String listenerName) 963 { 964 final String name; 965 if (listenerName == null) 966 { 967 name = getFirstListenerName(); 968 } 969 else 970 { 971 name = StaticUtils.toLowerCase(listenerName); 972 } 973 974 final LDAPListenerConfig listenerCfg = ldapListenerConfigs.get(name); 975 if (listenerCfg == null) 976 { 977 return null; 978 } 979 else 980 { 981 return listenerCfg.getListenAddress(); 982 } 983 } 984 985 986 987 /** 988 * Retrieves the configured listen port for the first active listener. 989 * 990 * @return The configured listen port for the first active listener, or -1 if 991 * there are no active listeners. 992 */ 993 public int getListenPort() 994 { 995 return getListenPort(null); 996 } 997 998 999 1000 /** 1001 * Retrieves the configured listen port for the specified listener, if 1002 * available. 1003 * 1004 * @param listenerName The name of the listener for which to retrieve the 1005 * listen port. It may be {@code null} in order to 1006 * obtain the listen port for the first active 1007 * listener. 1008 * 1009 * @return The configured listen port for the specified listener, or -1 if 1010 * there is no such listener or the listener is not active. 1011 */ 1012 public synchronized int getListenPort(@Nullable final String listenerName) 1013 { 1014 final String name; 1015 if (listenerName == null) 1016 { 1017 name = getFirstListenerName(); 1018 } 1019 else 1020 { 1021 name = StaticUtils.toLowerCase(listenerName); 1022 } 1023 1024 final LDAPListener listener = listeners.get(name); 1025 if (listener == null) 1026 { 1027 return -1; 1028 } 1029 else 1030 { 1031 return listener.getListenPort(); 1032 } 1033 } 1034 1035 1036 1037 /** 1038 * Retrieves the configured client socket factory for the first active 1039 * listener. 1040 * 1041 * @return The configured client socket factory for the first active 1042 * listener, or {@code null} if that listener does not have an 1043 * explicitly-configured socket factory or there are no active 1044 * listeners. 1045 */ 1046 @Nullable() 1047 public SocketFactory getClientSocketFactory() 1048 { 1049 return getClientSocketFactory(null); 1050 } 1051 1052 1053 1054 /** 1055 * Retrieves the configured client socket factory for the specified listener, 1056 * if available. 1057 * 1058 * @param listenerName The name of the listener for which to retrieve the 1059 * client socket factory. It may be {@code null} in 1060 * order to obtain the client socket factory for the 1061 * first active listener. 1062 * 1063 * @return The configured client socket factory for the specified listener, 1064 * or {@code null} if there is no such listener or that listener does 1065 * not have an explicitly-configured client socket factory. 1066 */ 1067 @Nullable() 1068 public synchronized SocketFactory getClientSocketFactory( 1069 @Nullable final String listenerName) 1070 { 1071 final String name; 1072 if (listenerName == null) 1073 { 1074 name = getFirstListenerName(); 1075 } 1076 else 1077 { 1078 name = StaticUtils.toLowerCase(listenerName); 1079 } 1080 1081 return clientSocketFactories.get(name); 1082 } 1083 1084 1085 1086 /** 1087 * Retrieves the name of the first running listener. 1088 * 1089 * @return The name of the first running listener, or {@code null} if there 1090 * are no active listeners. 1091 */ 1092 @Nullable() 1093 private String getFirstListenerName() 1094 { 1095 for (final Map.Entry<String,LDAPListenerConfig> e : 1096 ldapListenerConfigs.entrySet()) 1097 { 1098 final String name = e.getKey(); 1099 if (listeners.containsKey(name)) 1100 { 1101 return name; 1102 } 1103 } 1104 1105 return null; 1106 } 1107 1108 1109 1110 /** 1111 * Retrieves the delay in milliseconds that the server should impose before 1112 * beginning processing for operations. 1113 * 1114 * @return The delay in milliseconds that the server should impose before 1115 * beginning processing for operations, or 0 if there should be no 1116 * delay inserted when processing operations. 1117 */ 1118 public long getProcessingDelayMillis() 1119 { 1120 return inMemoryHandler.getProcessingDelayMillis(); 1121 } 1122 1123 1124 1125 /** 1126 * Specifies the delay in milliseconds that the server should impose before 1127 * beginning processing for operations. 1128 * 1129 * @param processingDelayMillis The delay in milliseconds that the server 1130 * should impose before beginning processing 1131 * for operations. A value less than or equal 1132 * to zero may be used to indicate that there 1133 * should be no delay. 1134 */ 1135 public void setProcessingDelayMillis(final long processingDelayMillis) 1136 { 1137 inMemoryHandler.setProcessingDelayMillis(processingDelayMillis); 1138 } 1139 1140 1141 1142 /** 1143 * Retrieves the number of entries currently held in the server. The count 1144 * returned will not include entries which are part of the changelog. 1145 * <BR><BR> 1146 * This method may be used regardless of whether the server is listening for 1147 * client connections. 1148 * 1149 * @return The number of entries currently held in the server. 1150 */ 1151 public int countEntries() 1152 { 1153 return countEntries(false); 1154 } 1155 1156 1157 1158 /** 1159 * Retrieves the number of entries currently held in the server, optionally 1160 * including those entries which are part of the changelog. 1161 * <BR><BR> 1162 * This method may be used regardless of whether the server is listening for 1163 * client connections. 1164 * 1165 * @param includeChangeLog Indicates whether to include entries that are 1166 * part of the changelog in the count. 1167 * 1168 * @return The number of entries currently held in the server. 1169 */ 1170 public int countEntries(final boolean includeChangeLog) 1171 { 1172 return inMemoryHandler.countEntries(includeChangeLog); 1173 } 1174 1175 1176 1177 /** 1178 * Retrieves the number of entries currently held in the server whose DN 1179 * matches or is subordinate to the provided base DN. 1180 * <BR><BR> 1181 * This method may be used regardless of whether the server is listening for 1182 * client connections. 1183 * 1184 * @param baseDN The base DN to use for the determination. 1185 * 1186 * @return The number of entries currently held in the server whose DN 1187 * matches or is subordinate to the provided base DN. 1188 * 1189 * @throws LDAPException If the provided string cannot be parsed as a valid 1190 * DN. 1191 */ 1192 public int countEntriesBelow(@NotNull final String baseDN) 1193 throws LDAPException 1194 { 1195 return inMemoryHandler.countEntriesBelow(baseDN); 1196 } 1197 1198 1199 1200 /** 1201 * Removes all entries currently held in the server. If a changelog is 1202 * enabled, then all changelog entries will also be cleared but the base 1203 * "cn=changelog" entry will be retained. 1204 * <BR><BR> 1205 * This method may be used regardless of whether the server is listening for 1206 * client connections. 1207 */ 1208 public void clear() 1209 { 1210 inMemoryHandler.clear(); 1211 } 1212 1213 1214 1215 /** 1216 * Reads entries from the specified LDIF file and adds them to the server, 1217 * optionally clearing any existing entries before beginning to add the new 1218 * entries. If an error is encountered while adding entries from LDIF then 1219 * the server will remain populated with the data it held before the import 1220 * attempt (even if the {@code clear} is given with a value of {@code true}). 1221 * <BR><BR> 1222 * This method may be used regardless of whether the server is listening for 1223 * client connections. 1224 * 1225 * @param clear Indicates whether to remove all existing entries prior to 1226 * adding entries read from LDIF. 1227 * @param path The path to the LDIF file from which the entries should be 1228 * read. It must not be {@code null}. 1229 * 1230 * @return The number of entries read from LDIF and added to the server. 1231 * 1232 * @throws LDAPException If a problem occurs while reading entries or adding 1233 * them to the server. 1234 */ 1235 public int importFromLDIF(final boolean clear, @NotNull final String path) 1236 throws LDAPException 1237 { 1238 return importFromLDIF(clear, new File(path)); 1239 } 1240 1241 1242 1243 /** 1244 * Reads entries from the specified LDIF file and adds them to the server, 1245 * optionally clearing any existing entries before beginning to add the new 1246 * entries. If an error is encountered while adding entries from LDIF then 1247 * the server will remain populated with the data it held before the import 1248 * attempt (even if the {@code clear} is given with a value of {@code true}). 1249 * <BR><BR> 1250 * This method may be used regardless of whether the server is listening for 1251 * client connections. 1252 * 1253 * @param clear Indicates whether to remove all existing entries prior to 1254 * adding entries read from LDIF. 1255 * @param ldifFile The LDIF file from which the entries should be read. It 1256 * must not be {@code null}. 1257 * 1258 * @return The number of entries read from LDIF and added to the server. 1259 * 1260 * @throws LDAPException If a problem occurs while reading entries or adding 1261 * them to the server. 1262 */ 1263 public int importFromLDIF(final boolean clear, @NotNull final File ldifFile) 1264 throws LDAPException 1265 { 1266 final LDIFReader reader; 1267 try 1268 { 1269 reader = new LDIFReader(ldifFile); 1270 1271 final Schema schema = getSchema(); 1272 if (schema != null) 1273 { 1274 reader.setSchema(schema); 1275 } 1276 } 1277 catch (final Exception e) 1278 { 1279 Debug.debugException(e); 1280 throw new LDAPException(ResultCode.LOCAL_ERROR, 1281 ERR_MEM_DS_INIT_FROM_LDIF_CANNOT_CREATE_READER.get( 1282 ldifFile.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1283 e); 1284 } 1285 1286 return importFromLDIF(clear, reader); 1287 } 1288 1289 1290 1291 /** 1292 * Reads entries from the provided LDIF reader and adds them to the server, 1293 * optionally clearing any existing entries before beginning to add the new 1294 * entries. If an error is encountered while adding entries from LDIF then 1295 * the server will remain populated with the data it held before the import 1296 * attempt (even if the {@code clear} is given with a value of {@code true}). 1297 * <BR><BR> 1298 * This method may be used regardless of whether the server is listening for 1299 * client connections. 1300 * 1301 * @param clear Indicates whether to remove all existing entries prior to 1302 * adding entries read from LDIF. 1303 * @param reader The LDIF reader to use to obtain the entries to be 1304 * imported. 1305 * 1306 * @return The number of entries read from LDIF and added to the server. 1307 * 1308 * @throws LDAPException If a problem occurs while reading entries or adding 1309 * them to the server. 1310 */ 1311 public int importFromLDIF(final boolean clear, 1312 @NotNull final LDIFReader reader) 1313 throws LDAPException 1314 { 1315 return inMemoryHandler.importFromLDIF(clear, reader); 1316 } 1317 1318 1319 1320 /** 1321 * Writes the current contents of the server in LDIF form to the specified 1322 * file. 1323 * <BR><BR> 1324 * This method may be used regardless of whether the server is listening for 1325 * client connections. 1326 * 1327 * @param path The path of the file to which the LDIF 1328 * entries should be written. 1329 * @param excludeGeneratedAttrs Indicates whether to exclude automatically 1330 * generated operational attributes like 1331 * entryUUID, entryDN, creatorsName, etc. 1332 * @param excludeChangeLog Indicates whether to exclude entries 1333 * contained in the changelog. 1334 * 1335 * @return The number of entries written to LDIF. 1336 * 1337 * @throws LDAPException If a problem occurs while writing entries to LDIF. 1338 */ 1339 public int exportToLDIF(@NotNull final String path, 1340 final boolean excludeGeneratedAttrs, 1341 final boolean excludeChangeLog) 1342 throws LDAPException 1343 { 1344 final LDIFWriter ldifWriter; 1345 try 1346 { 1347 ldifWriter = new LDIFWriter(path); 1348 } 1349 catch (final Exception e) 1350 { 1351 Debug.debugException(e); 1352 throw new LDAPException(ResultCode.LOCAL_ERROR, 1353 ERR_MEM_DS_EXPORT_TO_LDIF_CANNOT_CREATE_WRITER.get(path, 1354 StaticUtils.getExceptionMessage(e)), 1355 e); 1356 } 1357 1358 return exportToLDIF(ldifWriter, excludeGeneratedAttrs, excludeChangeLog, 1359 true); 1360 } 1361 1362 1363 1364 /** 1365 * Writes the current contents of the server in LDIF form using the provided 1366 * LDIF writer. 1367 * <BR><BR> 1368 * This method may be used regardless of whether the server is listening for 1369 * client connections. 1370 * 1371 * @param ldifWriter The LDIF writer to use when writing the 1372 * entries. It must not be {@code null}. 1373 * @param excludeGeneratedAttrs Indicates whether to exclude automatically 1374 * generated operational attributes like 1375 * entryUUID, entryDN, creatorsName, etc. 1376 * @param excludeChangeLog Indicates whether to exclude entries 1377 * contained in the changelog. 1378 * @param closeWriter Indicates whether the LDIF writer should be 1379 * closed after all entries have been written. 1380 * 1381 * @return The number of entries written to LDIF. 1382 * 1383 * @throws LDAPException If a problem occurs while writing entries to LDIF. 1384 */ 1385 public int exportToLDIF(@NotNull final LDIFWriter ldifWriter, 1386 final boolean excludeGeneratedAttrs, 1387 final boolean excludeChangeLog, 1388 final boolean closeWriter) 1389 throws LDAPException 1390 { 1391 return inMemoryHandler.exportToLDIF(ldifWriter, excludeGeneratedAttrs, 1392 excludeChangeLog, closeWriter); 1393 } 1394 1395 1396 1397 /** 1398 * Reads LDIF change records from the specified LDIF file and applies them 1399 * to the data in the server. Any LDIF records without a changetype will be 1400 * treated as add change records. If an error is encountered while attempting 1401 * to apply the requested changes, then the server will remain populated with 1402 * the data it held before this method was called, even if earlier changes 1403 * could have been applied successfully. 1404 * <BR><BR> 1405 * This method may be used regardless of whether the server is listening for 1406 * client connections. 1407 * 1408 * @param path The path to the LDIF file from which the LDIF change 1409 * records should be read. It must not be {@code null}. 1410 * 1411 * @return The number of changes applied from the LDIF file. 1412 * 1413 * @throws LDAPException If a problem occurs while reading change records 1414 * or applying them to the server. 1415 */ 1416 public int applyChangesFromLDIF(@NotNull final String path) 1417 throws LDAPException 1418 { 1419 return applyChangesFromLDIF(new File(path)); 1420 } 1421 1422 1423 1424 /** 1425 * Reads LDIF change records from the specified LDIF file and applies them 1426 * to the data in the server. Any LDIF records without a changetype will be 1427 * treated as add change records. If an error is encountered while attempting 1428 * to apply the requested changes, then the server will remain populated with 1429 * the data it held before this method was called, even if earlier changes 1430 * could have been applied successfully. 1431 * <BR><BR> 1432 * This method may be used regardless of whether the server is listening for 1433 * client connections. 1434 * 1435 * @param ldifFile The LDIF file from which the LDIF change records should 1436 * be read. It must not be {@code null}. 1437 * 1438 * @return The number of changes applied from the LDIF file. 1439 * 1440 * @throws LDAPException If a problem occurs while reading change records 1441 * or applying them to the server. 1442 */ 1443 public int applyChangesFromLDIF(@NotNull final File ldifFile) 1444 throws LDAPException 1445 { 1446 final LDIFReader reader; 1447 try 1448 { 1449 reader = new LDIFReader(ldifFile); 1450 1451 final Schema schema = getSchema(); 1452 if (schema != null) 1453 { 1454 reader.setSchema(schema); 1455 } 1456 } 1457 catch (final Exception e) 1458 { 1459 Debug.debugException(e); 1460 throw new LDAPException(ResultCode.LOCAL_ERROR, 1461 ERR_MEM_DS_APPLY_CHANGES_FROM_LDIF_CANNOT_CREATE_READER.get( 1462 ldifFile.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), 1463 e); 1464 } 1465 1466 return applyChangesFromLDIF(reader); 1467 } 1468 1469 1470 1471 /** 1472 * Reads LDIF change records from the provided LDIF reader file and applies 1473 * them to the data in the server. Any LDIF records without a changetype will 1474 * be treated as add change records. If an error is encountered while 1475 * attempting to apply the requested changes, then the server will remain 1476 * populated with the data it held before this method was called, even if 1477 * earlier changes could have been applied successfully. 1478 * <BR><BR> 1479 * This method may be used regardless of whether the server is listening for 1480 * client connections. 1481 * 1482 * @param reader The LDIF reader to use to obtain the change records to be 1483 * applied. 1484 * 1485 * @return The number of changes applied from the LDIF file. 1486 * 1487 * @throws LDAPException If a problem occurs while reading change records 1488 * or applying them to the server. 1489 */ 1490 public int applyChangesFromLDIF(@NotNull final LDIFReader reader) 1491 throws LDAPException 1492 { 1493 return inMemoryHandler.applyChangesFromLDIF(reader); 1494 } 1495 1496 1497 1498 /** 1499 * {@inheritDoc} 1500 * <BR><BR> 1501 * This method may be used regardless of whether the server is listening for 1502 * client connections. 1503 */ 1504 @Override() 1505 @Nullable() 1506 public RootDSE getRootDSE() 1507 throws LDAPException 1508 { 1509 return new RootDSE(inMemoryHandler.getEntry("")); 1510 } 1511 1512 1513 1514 /** 1515 * {@inheritDoc} 1516 * <BR><BR> 1517 * This method may be used regardless of whether the server is listening for 1518 * client connections. 1519 */ 1520 @Override() 1521 @Nullable() 1522 public Schema getSchema() 1523 throws LDAPException 1524 { 1525 return inMemoryHandler.getSchema(); 1526 } 1527 1528 1529 1530 /** 1531 * {@inheritDoc} 1532 * <BR><BR> 1533 * This method may be used regardless of whether the server is listening for 1534 * client connections. 1535 */ 1536 @Override() 1537 @Nullable() 1538 public Schema getSchema(@Nullable final String entryDN) 1539 throws LDAPException 1540 { 1541 return inMemoryHandler.getSchema(); 1542 } 1543 1544 1545 1546 /** 1547 * {@inheritDoc} 1548 * <BR><BR> 1549 * This method may be used regardless of whether the server is listening for 1550 * client connections. 1551 */ 1552 @Override() 1553 @Nullable() 1554 public SearchResultEntry getEntry(@NotNull final String dn) 1555 throws LDAPException 1556 { 1557 return searchForEntry(dn, SearchScope.BASE, 1558 Filter.createPresenceFilter("objectClass")); 1559 } 1560 1561 1562 1563 /** 1564 * {@inheritDoc} 1565 * <BR><BR> 1566 * This method may be used regardless of whether the server is listening for 1567 * client connections, and regardless of whether search operations are 1568 * allowed in the server. 1569 */ 1570 @Override() 1571 @Nullable() 1572 public SearchResultEntry getEntry(@NotNull final String dn, 1573 @Nullable final String... attributes) 1574 throws LDAPException 1575 { 1576 return searchForEntry(dn, SearchScope.BASE, 1577 Filter.createPresenceFilter("objectClass"), attributes); 1578 } 1579 1580 1581 1582 /** 1583 * {@inheritDoc} 1584 * <BR><BR> 1585 * This method may be used regardless of whether the server is listening for 1586 * client connections, and regardless of whether add operations are allowed in 1587 * the server. 1588 */ 1589 @Override() 1590 @NotNull() 1591 public LDAPResult add(@NotNull final String dn, 1592 @NotNull final Attribute... attributes) 1593 throws LDAPException 1594 { 1595 return add(new AddRequest(dn, attributes)); 1596 } 1597 1598 1599 1600 /** 1601 * {@inheritDoc} 1602 * <BR><BR> 1603 * This method may be used regardless of whether the server is listening for 1604 * client connections, and regardless of whether add operations are allowed in 1605 * the server. 1606 */ 1607 @Override() 1608 @NotNull() 1609 public LDAPResult add(@NotNull final String dn, 1610 @NotNull final Collection<Attribute> attributes) 1611 throws LDAPException 1612 { 1613 return add(new AddRequest(dn, attributes)); 1614 } 1615 1616 1617 1618 /** 1619 * {@inheritDoc} 1620 * <BR><BR> 1621 * This method may be used regardless of whether the server is listening for 1622 * client connections, and regardless of whether add operations are allowed in 1623 * the server. 1624 */ 1625 @Override() 1626 @NotNull() 1627 public LDAPResult add(@NotNull final Entry entry) 1628 throws LDAPException 1629 { 1630 return add(new AddRequest(entry)); 1631 } 1632 1633 1634 1635 /** 1636 * {@inheritDoc} 1637 * <BR><BR> 1638 * This method may be used regardless of whether the server is listening for 1639 * client connections, and regardless of whether add operations are allowed in 1640 * the server. 1641 */ 1642 @Override() 1643 @NotNull() 1644 public LDAPResult add(@NotNull final String... ldifLines) 1645 throws LDIFException, LDAPException 1646 { 1647 return add(new AddRequest(ldifLines)); 1648 } 1649 1650 1651 1652 /** 1653 * {@inheritDoc} 1654 * <BR><BR> 1655 * This method may be used regardless of whether the server is listening for 1656 * client connections, and regardless of whether add operations are allowed in 1657 * the server. 1658 */ 1659 @Override() 1660 @NotNull() 1661 public LDAPResult add(@NotNull final AddRequest addRequest) 1662 throws LDAPException 1663 { 1664 return inMemoryHandler.add(addRequest); 1665 } 1666 1667 1668 1669 /** 1670 * {@inheritDoc} 1671 * <BR><BR> 1672 * This method may be used regardless of whether the server is listening for 1673 * client connections, and regardless of whether add operations are allowed in 1674 * the server. 1675 */ 1676 @Override() 1677 @NotNull() 1678 public LDAPResult add(@NotNull final ReadOnlyAddRequest addRequest) 1679 throws LDAPException 1680 { 1681 return add(addRequest.duplicate()); 1682 } 1683 1684 1685 1686 /** 1687 * Attempts to add all of the provided entries to the server. If a problem is 1688 * encountered while attempting to add any of the provided entries, then the 1689 * server will remain populated with the data it held before this method was 1690 * called. 1691 * <BR><BR> 1692 * This method may be used regardless of whether the server is listening for 1693 * client connections, and regardless of whether add operations are allowed in 1694 * the server. 1695 * 1696 * @param entries The entries to be added to the server. 1697 * 1698 * @throws LDAPException If a problem is encountered while attempting to add 1699 * any of the provided entries. 1700 */ 1701 public void addEntries(@NotNull final Entry... entries) 1702 throws LDAPException 1703 { 1704 addEntries(Arrays.asList(entries)); 1705 } 1706 1707 1708 1709 /** 1710 * Attempts to add all of the provided entries to the server. If a problem is 1711 * encountered while attempting to add any of the provided entries, then the 1712 * server will remain populated with the data it held before this method was 1713 * called. 1714 * <BR><BR> 1715 * This method may be used regardless of whether the server is listening for 1716 * client connections, and regardless of whether add operations are allowed in 1717 * the server. 1718 * 1719 * @param entries The entries to be added to the server. 1720 * 1721 * @throws LDAPException If a problem is encountered while attempting to add 1722 * any of the provided entries. 1723 */ 1724 public void addEntries(@NotNull final List<? extends Entry> entries) 1725 throws LDAPException 1726 { 1727 inMemoryHandler.addEntries(entries); 1728 } 1729 1730 1731 1732 /** 1733 * Attempts to add a set of entries provided in LDIF form in which each 1734 * element of the provided array is a line of the LDIF representation, with 1735 * empty strings as separators between entries (as you would have for blank 1736 * lines in an LDIF file). If a problem is encountered while attempting to 1737 * add any of the provided entries, then the server will remain populated with 1738 * the data it held before this method was called. 1739 * <BR><BR> 1740 * This method may be used regardless of whether the server is listening for 1741 * client connections, and regardless of whether add operations are allowed in 1742 * the server. 1743 * 1744 * @param ldifEntryLines The lines comprising the LDIF representation of the 1745 * entries to be added. 1746 * 1747 * @throws LDAPException If a problem is encountered while attempting to add 1748 * any of the provided entries. 1749 */ 1750 public void addEntries(@NotNull final String... ldifEntryLines) 1751 throws LDAPException 1752 { 1753 final ByteStringBuffer buffer = new ByteStringBuffer(); 1754 for (final String line : ldifEntryLines) 1755 { 1756 buffer.append(line); 1757 buffer.append(StaticUtils.EOL_BYTES); 1758 } 1759 1760 final ArrayList<Entry> entryList = new ArrayList<>(10); 1761 final LDIFReader reader = new LDIFReader(buffer.asInputStream()); 1762 1763 final Schema schema = getSchema(); 1764 if (schema != null) 1765 { 1766 reader.setSchema(schema); 1767 } 1768 1769 while (true) 1770 { 1771 try 1772 { 1773 final Entry entry = reader.readEntry(); 1774 if (entry == null) 1775 { 1776 break; 1777 } 1778 else 1779 { 1780 entryList.add(entry); 1781 } 1782 } 1783 catch (final Exception e) 1784 { 1785 Debug.debugException(e); 1786 throw new LDAPException(ResultCode.PARAM_ERROR, 1787 ERR_MEM_DS_ADD_ENTRIES_LDIF_PARSE_EXCEPTION.get( 1788 StaticUtils.getExceptionMessage(e)), 1789 e); 1790 } 1791 } 1792 1793 addEntries(entryList); 1794 } 1795 1796 1797 1798 /** 1799 * Processes a simple bind request with the provided DN and password. Note 1800 * that the bind processing will verify that the provided credentials are 1801 * valid, but it will not alter the server in any way. 1802 * 1803 * @param bindDN The bind DN for the bind operation. 1804 * @param password The password for the simple bind operation. 1805 * 1806 * @return The result of processing the bind operation. 1807 * 1808 * @throws LDAPException If the server rejects the bind request, or if a 1809 * problem occurs while sending the request or reading 1810 * the response. 1811 */ 1812 @NotNull() 1813 public BindResult bind(@Nullable final String bindDN, 1814 @Nullable final String password) 1815 throws LDAPException 1816 { 1817 return bind(new SimpleBindRequest(bindDN, password)); 1818 } 1819 1820 1821 1822 /** 1823 * Processes the provided bind request. Only simple and SASL PLAIN bind 1824 * requests are supported. Note that the bind processing will verify that the 1825 * provided credentials are valid, but it will not alter the server in any 1826 * way. 1827 * 1828 * @param bindRequest The bind request to be processed. It must not be 1829 * {@code null}. 1830 * 1831 * @return The result of processing the bind operation. 1832 * 1833 * @throws LDAPException If the server rejects the bind request, or if a 1834 * problem occurs while sending the request or reading 1835 * the response. 1836 */ 1837 @NotNull() 1838 public BindResult bind(@NotNull final BindRequest bindRequest) 1839 throws LDAPException 1840 { 1841 final ArrayList<Control> requestControlList = 1842 new ArrayList<>(bindRequest.getControlList()); 1843 requestControlList.add(new Control( 1844 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false)); 1845 1846 final BindRequestProtocolOp bindOp; 1847 if (bindRequest instanceof SimpleBindRequest) 1848 { 1849 final SimpleBindRequest r = (SimpleBindRequest) bindRequest; 1850 bindOp = new BindRequestProtocolOp(r.getBindDN(), 1851 r.getPassword().getValue()); 1852 } 1853 else if (bindRequest instanceof PLAINBindRequest) 1854 { 1855 final PLAINBindRequest r = (PLAINBindRequest) bindRequest; 1856 1857 // Create the byte array that should comprise the credentials. 1858 final byte[] authZIDBytes = StaticUtils.getBytes(r.getAuthorizationID()); 1859 final byte[] authNIDBytes = StaticUtils.getBytes(r.getAuthenticationID()); 1860 final byte[] passwordBytes = r.getPasswordBytes(); 1861 1862 final byte[] credBytes = new byte[2 + authZIDBytes.length + 1863 authNIDBytes.length + passwordBytes.length]; 1864 System.arraycopy(authZIDBytes, 0, credBytes, 0, authZIDBytes.length); 1865 1866 int pos = authZIDBytes.length + 1; 1867 System.arraycopy(authNIDBytes, 0, credBytes, pos, authNIDBytes.length); 1868 1869 pos += authNIDBytes.length + 1; 1870 System.arraycopy(passwordBytes, 0, credBytes, pos, passwordBytes.length); 1871 1872 bindOp = new BindRequestProtocolOp(null, "PLAIN", 1873 new ASN1OctetString(credBytes)); 1874 } 1875 else 1876 { 1877 throw new LDAPException(ResultCode.AUTH_METHOD_NOT_SUPPORTED, 1878 ERR_MEM_DS_UNSUPPORTED_BIND_TYPE.get()); 1879 } 1880 1881 final LDAPMessage responseMessage = inMemoryHandler.processBindRequest(1, 1882 bindOp, requestControlList); 1883 final BindResponseProtocolOp bindResponse = 1884 responseMessage.getBindResponseProtocolOp(); 1885 1886 final BindResult bindResult = new BindResult(new LDAPResult( 1887 responseMessage.getMessageID(), 1888 ResultCode.valueOf(bindResponse.getResultCode()), 1889 bindResponse.getDiagnosticMessage(), bindResponse.getMatchedDN(), 1890 bindResponse.getReferralURLs(), responseMessage.getControls())); 1891 1892 switch (bindResponse.getResultCode()) 1893 { 1894 case ResultCode.SUCCESS_INT_VALUE: 1895 return bindResult; 1896 default: 1897 throw new LDAPException(bindResult); 1898 } 1899 } 1900 1901 1902 1903 /** 1904 * {@inheritDoc} 1905 * <BR><BR> 1906 * This method may be used regardless of whether the server is listening for 1907 * client connections, and regardless of whether compare operations are 1908 * allowed in the server. 1909 */ 1910 @Override() 1911 @NotNull() 1912 public CompareResult compare(@NotNull final String dn, 1913 @NotNull final String attributeName, 1914 @NotNull final String assertionValue) 1915 throws LDAPException 1916 { 1917 return compare(new CompareRequest(dn, attributeName, assertionValue)); 1918 } 1919 1920 1921 1922 /** 1923 * {@inheritDoc} 1924 * <BR><BR> 1925 * This method may be used regardless of whether the server is listening for 1926 * client connections, and regardless of whether compare operations are 1927 * allowed in the server. 1928 */ 1929 @Override() 1930 @NotNull() 1931 public CompareResult compare(@NotNull final CompareRequest compareRequest) 1932 throws LDAPException 1933 { 1934 final ArrayList<Control> requestControlList = 1935 new ArrayList<>(compareRequest.getControlList()); 1936 requestControlList.add(new Control( 1937 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false)); 1938 1939 final LDAPMessage responseMessage = inMemoryHandler.processCompareRequest(1, 1940 new CompareRequestProtocolOp(compareRequest.getDN(), 1941 compareRequest.getAttributeName(), 1942 compareRequest.getRawAssertionValue()), 1943 requestControlList); 1944 1945 final CompareResponseProtocolOp compareResponse = 1946 responseMessage.getCompareResponseProtocolOp(); 1947 1948 final LDAPResult compareResult = new LDAPResult( 1949 responseMessage.getMessageID(), 1950 ResultCode.valueOf(compareResponse.getResultCode()), 1951 compareResponse.getDiagnosticMessage(), compareResponse.getMatchedDN(), 1952 compareResponse.getReferralURLs(), responseMessage.getControls()); 1953 1954 switch (compareResponse.getResultCode()) 1955 { 1956 case ResultCode.COMPARE_TRUE_INT_VALUE: 1957 case ResultCode.COMPARE_FALSE_INT_VALUE: 1958 return new CompareResult(compareResult); 1959 default: 1960 throw new LDAPException(compareResult); 1961 } 1962 } 1963 1964 1965 1966 /** 1967 * {@inheritDoc} 1968 * <BR><BR> 1969 * This method may be used regardless of whether the server is listening for 1970 * client connections, and regardless of whether compare operations are 1971 * allowed in the server. 1972 */ 1973 @Override() 1974 @NotNull() 1975 public CompareResult compare( 1976 @NotNull final ReadOnlyCompareRequest compareRequest) 1977 throws LDAPException 1978 { 1979 return compare(compareRequest.duplicate()); 1980 } 1981 1982 1983 1984 /** 1985 * {@inheritDoc} 1986 * <BR><BR> 1987 * This method may be used regardless of whether the server is listening for 1988 * client connections, and regardless of whether delete operations are 1989 * allowed in the server. 1990 */ 1991 @Override() 1992 @NotNull() 1993 public LDAPResult delete(@NotNull final String dn) 1994 throws LDAPException 1995 { 1996 return delete(new DeleteRequest(dn)); 1997 } 1998 1999 2000 2001 /** 2002 * {@inheritDoc} 2003 * <BR><BR> 2004 * This method may be used regardless of whether the server is listening for 2005 * client connections, and regardless of whether delete operations are 2006 * allowed in the server. 2007 */ 2008 @Override() 2009 @NotNull() 2010 public LDAPResult delete(@NotNull final DeleteRequest deleteRequest) 2011 throws LDAPException 2012 { 2013 return inMemoryHandler.delete(deleteRequest); 2014 } 2015 2016 2017 2018 /** 2019 * {@inheritDoc} 2020 * <BR><BR> 2021 * This method may be used regardless of whether the server is listening for 2022 * client connections, and regardless of whether delete operations are 2023 * allowed in the server. 2024 */ 2025 @Override() 2026 @NotNull() 2027 public LDAPResult delete(@NotNull final ReadOnlyDeleteRequest deleteRequest) 2028 throws LDAPException 2029 { 2030 return delete(deleteRequest.duplicate()); 2031 } 2032 2033 2034 2035 /** 2036 * Attempts to delete the specified entry and all entries below it from the 2037 * server. 2038 * <BR><BR> 2039 * This method may be used regardless of whether the server is listening for 2040 * client connections, and regardless of whether compare operations are 2041 * allowed in the server. 2042 * 2043 * @param baseDN The DN of the entry to remove, along with all of its 2044 * subordinates. 2045 * 2046 * @return The number of entries removed from the server, or zero if the 2047 * specified entry was not found. 2048 * 2049 * @throws LDAPException If a problem is encountered while attempting to 2050 * remove the entries. 2051 */ 2052 public int deleteSubtree(@NotNull final String baseDN) 2053 throws LDAPException 2054 { 2055 return inMemoryHandler.deleteSubtree(baseDN); 2056 } 2057 2058 2059 2060 /** 2061 * Processes an extended request with the provided request OID. Note that 2062 * because some types of extended operations return unusual result codes under 2063 * "normal" conditions, the server may not always throw an exception for a 2064 * failed extended operation like it does for other types of operations. It 2065 * will throw an exception under conditions where there appears to be a 2066 * problem with the connection or the server to which the connection is 2067 * established, but there may be many circumstances in which an extended 2068 * operation is not processed correctly but this method does not throw an 2069 * exception. In the event that no exception is thrown, it is the 2070 * responsibility of the caller to interpret the result to determine whether 2071 * the operation was processed as expected. 2072 * <BR><BR> 2073 * This method may be used regardless of whether the server is listening for 2074 * client connections, and regardless of whether extended operations are 2075 * allowed in the server. 2076 * 2077 * @param requestOID The OID for the extended request to process. It must 2078 * not be {@code null}. 2079 * 2080 * @return The extended result object that provides information about the 2081 * result of the request processing. It may or may not indicate that 2082 * the operation was successful. 2083 * 2084 * @throws LDAPException If a problem occurs while sending the request or 2085 * reading the response. 2086 */ 2087 @NotNull() 2088 public ExtendedResult processExtendedOperation( 2089 @NotNull final String requestOID) 2090 throws LDAPException 2091 { 2092 Validator.ensureNotNull(requestOID); 2093 2094 return processExtendedOperation(new ExtendedRequest(requestOID)); 2095 } 2096 2097 2098 2099 /** 2100 * Processes an extended request with the provided request OID and value. 2101 * Note that because some types of extended operations return unusual result 2102 * codes under "normal" conditions, the server may not always throw an 2103 * exception for a failed extended operation like it does for other types of 2104 * operations. It will throw an exception under conditions where there 2105 * appears to be a problem with the connection or the server to which the 2106 * connection is established, but there may be many circumstances in which an 2107 * extended operation is not processed correctly but this method does not 2108 * throw an exception. In the event that no exception is thrown, it is the 2109 * responsibility of the caller to interpret the result to determine whether 2110 * the operation was processed as expected. 2111 * <BR><BR> 2112 * This method may be used regardless of whether the server is listening for 2113 * client connections, and regardless of whether extended operations are 2114 * allowed in the server. 2115 * 2116 * @param requestOID The OID for the extended request to process. It must 2117 * not be {@code null}. 2118 * @param requestValue The encoded value for the extended request to 2119 * process. It may be {@code null} if there does not 2120 * need to be a value for the requested operation. 2121 * 2122 * @return The extended result object that provides information about the 2123 * result of the request processing. It may or may not indicate that 2124 * the operation was successful. 2125 * 2126 * @throws LDAPException If a problem occurs while sending the request or 2127 * reading the response. 2128 */ 2129 @NotNull() 2130 public ExtendedResult processExtendedOperation( 2131 @NotNull final String requestOID, 2132 @Nullable final ASN1OctetString requestValue) 2133 throws LDAPException 2134 { 2135 Validator.ensureNotNull(requestOID); 2136 2137 return processExtendedOperation(new ExtendedRequest(requestOID, 2138 requestValue)); 2139 } 2140 2141 2142 2143 /** 2144 * Processes the provided extended request. Note that because some types of 2145 * extended operations return unusual result codes under "normal" conditions, 2146 * the server may not always throw an exception for a failed extended 2147 * operation like it does for other types of operations. It will throw an 2148 * exception under conditions where there appears to be a problem with the 2149 * connection or the server to which the connection is established, but there 2150 * may be many circumstances in which an extended operation is not processed 2151 * correctly but this method does not throw an exception. In the event that 2152 * no exception is thrown, it is the responsibility of the caller to interpret 2153 * the result to determine whether the operation was processed as expected. 2154 * <BR><BR> 2155 * This method may be used regardless of whether the server is listening for 2156 * client connections, and regardless of whether extended operations are 2157 * allowed in the server. 2158 * 2159 * @param extendedRequest The extended request to be processed. It must not 2160 * be {@code null}. 2161 * 2162 * @return The extended result object that provides information about the 2163 * result of the request processing. It may or may not indicate that 2164 * the operation was successful. 2165 * 2166 * @throws LDAPException If a problem occurs while sending the request or 2167 * reading the response. 2168 */ 2169 @NotNull() 2170 public ExtendedResult processExtendedOperation( 2171 @NotNull final ExtendedRequest extendedRequest) 2172 throws LDAPException 2173 { 2174 Validator.ensureNotNull(extendedRequest); 2175 2176 final ArrayList<Control> requestControlList = 2177 new ArrayList<>(extendedRequest.getControlList()); 2178 requestControlList.add(new Control( 2179 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false)); 2180 2181 2182 final LDAPMessage responseMessage = 2183 inMemoryHandler.processExtendedRequest(1, 2184 new ExtendedRequestProtocolOp(extendedRequest.getOID(), 2185 extendedRequest.getValue()), 2186 requestControlList); 2187 2188 final ExtendedResponseProtocolOp extendedResponse = 2189 responseMessage.getExtendedResponseProtocolOp(); 2190 2191 final ResultCode rc = ResultCode.valueOf(extendedResponse.getResultCode()); 2192 2193 final String[] referralURLs; 2194 final List<String> referralURLList = extendedResponse.getReferralURLs(); 2195 if ((referralURLList == null) || referralURLList.isEmpty()) 2196 { 2197 referralURLs = StaticUtils.NO_STRINGS; 2198 } 2199 else 2200 { 2201 referralURLs = new String[referralURLList.size()]; 2202 referralURLList.toArray(referralURLs); 2203 } 2204 2205 final Control[] responseControls; 2206 final List<Control> controlList = responseMessage.getControls(); 2207 if ((controlList == null) || controlList.isEmpty()) 2208 { 2209 responseControls = StaticUtils.NO_CONTROLS; 2210 } 2211 else 2212 { 2213 responseControls = new Control[controlList.size()]; 2214 controlList.toArray(responseControls); 2215 } 2216 2217 final ExtendedResult extendedResult = new ExtendedResult( 2218 responseMessage.getMessageID(), rc, 2219 extendedResponse.getDiagnosticMessage(), 2220 extendedResponse.getMatchedDN(), referralURLs, 2221 extendedResponse.getResponseOID(), 2222 extendedResponse.getResponseValue(), responseControls); 2223 2224 if ((extendedResult.getOID() == null) && 2225 (extendedResult.getValue() == null)) 2226 { 2227 switch (rc.intValue()) 2228 { 2229 case ResultCode.OPERATIONS_ERROR_INT_VALUE: 2230 case ResultCode.PROTOCOL_ERROR_INT_VALUE: 2231 case ResultCode.BUSY_INT_VALUE: 2232 case ResultCode.UNAVAILABLE_INT_VALUE: 2233 case ResultCode.OTHER_INT_VALUE: 2234 case ResultCode.SERVER_DOWN_INT_VALUE: 2235 case ResultCode.LOCAL_ERROR_INT_VALUE: 2236 case ResultCode.ENCODING_ERROR_INT_VALUE: 2237 case ResultCode.DECODING_ERROR_INT_VALUE: 2238 case ResultCode.TIMEOUT_INT_VALUE: 2239 case ResultCode.NO_MEMORY_INT_VALUE: 2240 case ResultCode.CONNECT_ERROR_INT_VALUE: 2241 throw new LDAPException(extendedResult); 2242 } 2243 } 2244 2245 return extendedResult; 2246 } 2247 2248 2249 2250 /** 2251 * {@inheritDoc} 2252 * <BR><BR> 2253 * This method may be used regardless of whether the server is listening for 2254 * client connections, and regardless of whether modify operations are allowed 2255 * in the server. 2256 */ 2257 @Override() 2258 @NotNull() 2259 public LDAPResult modify(@NotNull final String dn, 2260 @NotNull final Modification mod) 2261 throws LDAPException 2262 { 2263 return modify(new ModifyRequest(dn, mod)); 2264 } 2265 2266 2267 2268 /** 2269 * {@inheritDoc} 2270 * <BR><BR> 2271 * This method may be used regardless of whether the server is listening for 2272 * client connections, and regardless of whether modify operations are allowed 2273 * in the server. 2274 */ 2275 @Override() 2276 @NotNull() 2277 public LDAPResult modify(@NotNull final String dn, 2278 @NotNull final Modification... mods) 2279 throws LDAPException 2280 { 2281 return modify(new ModifyRequest(dn, mods)); 2282 } 2283 2284 2285 2286 /** 2287 * {@inheritDoc} 2288 * <BR><BR> 2289 * This method may be used regardless of whether the server is listening for 2290 * client connections, and regardless of whether modify operations are allowed 2291 * in the server. 2292 */ 2293 @Override() 2294 @NotNull() 2295 public LDAPResult modify(@NotNull final String dn, 2296 @NotNull final List<Modification> mods) 2297 throws LDAPException 2298 { 2299 return modify(new ModifyRequest(dn, mods)); 2300 } 2301 2302 2303 2304 /** 2305 * {@inheritDoc} 2306 * <BR><BR> 2307 * This method may be used regardless of whether the server is listening for 2308 * client connections, and regardless of whether modify operations are allowed 2309 * in the server. 2310 */ 2311 @Override() 2312 @NotNull() 2313 public LDAPResult modify(@NotNull final String... ldifModificationLines) 2314 throws LDIFException, LDAPException 2315 { 2316 return modify(new ModifyRequest(ldifModificationLines)); 2317 } 2318 2319 2320 2321 /** 2322 * {@inheritDoc} 2323 * <BR><BR> 2324 * This method may be used regardless of whether the server is listening for 2325 * client connections, and regardless of whether modify operations are allowed 2326 * in the server. 2327 */ 2328 @Override() 2329 @NotNull() 2330 public LDAPResult modify(@NotNull final ModifyRequest modifyRequest) 2331 throws LDAPException 2332 { 2333 return inMemoryHandler.modify(modifyRequest); 2334 } 2335 2336 2337 2338 /** 2339 * {@inheritDoc} 2340 * <BR><BR> 2341 * This method may be used regardless of whether the server is listening for 2342 * client connections, and regardless of whether modify operations are allowed 2343 * in the server. 2344 */ 2345 @Override() 2346 @NotNull() 2347 public LDAPResult modify(@NotNull final ReadOnlyModifyRequest modifyRequest) 2348 throws LDAPException 2349 { 2350 return modify(modifyRequest.duplicate()); 2351 } 2352 2353 2354 2355 /** 2356 * {@inheritDoc} 2357 * <BR><BR> 2358 * This method may be used regardless of whether the server is listening for 2359 * client connections, and regardless of whether modify DN operations are 2360 * allowed in the server. 2361 */ 2362 @Override() 2363 @NotNull() 2364 public LDAPResult modifyDN(@NotNull final String dn, 2365 @NotNull final String newRDN, 2366 final boolean deleteOldRDN) 2367 throws LDAPException 2368 { 2369 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN)); 2370 } 2371 2372 2373 2374 /** 2375 * {@inheritDoc} 2376 * <BR><BR> 2377 * This method may be used regardless of whether the server is listening for 2378 * client connections, and regardless of whether modify DN operations are 2379 * allowed in the server. 2380 */ 2381 @Override() 2382 @NotNull() 2383 public LDAPResult modifyDN(@NotNull final String dn, 2384 @NotNull final String newRDN, 2385 final boolean deleteOldRDN, 2386 @Nullable final String newSuperiorDN) 2387 throws LDAPException 2388 { 2389 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN, 2390 newSuperiorDN)); 2391 } 2392 2393 2394 2395 /** 2396 * {@inheritDoc} 2397 * <BR><BR> 2398 * This method may be used regardless of whether the server is listening for 2399 * client connections, and regardless of whether modify DN operations are 2400 * allowed in the server. 2401 */ 2402 @Override() 2403 @NotNull() 2404 public LDAPResult modifyDN(@NotNull final ModifyDNRequest modifyDNRequest) 2405 throws LDAPException 2406 { 2407 return inMemoryHandler.modifyDN(modifyDNRequest); 2408 } 2409 2410 2411 2412 /** 2413 * {@inheritDoc} 2414 * <BR><BR> 2415 * This method may be used regardless of whether the server is listening for 2416 * client connections, and regardless of whether modify DN operations are 2417 * allowed in the server. 2418 */ 2419 @Override() 2420 @NotNull() 2421 public LDAPResult modifyDN( 2422 @NotNull final ReadOnlyModifyDNRequest modifyDNRequest) 2423 throws LDAPException 2424 { 2425 return modifyDN(modifyDNRequest.duplicate()); 2426 } 2427 2428 2429 2430 /** 2431 * {@inheritDoc} 2432 * <BR><BR> 2433 * This method may be used regardless of whether the server is listening for 2434 * client connections, and regardless of whether search operations are allowed 2435 * in the server. 2436 */ 2437 @Override() 2438 @NotNull() 2439 public SearchResult search(@NotNull final String baseDN, 2440 @NotNull final SearchScope scope, 2441 @NotNull final String filter, 2442 @Nullable final String... attributes) 2443 throws LDAPSearchException 2444 { 2445 return search(new SearchRequest(baseDN, scope, parseFilter(filter), 2446 attributes)); 2447 } 2448 2449 2450 2451 /** 2452 * {@inheritDoc} 2453 * <BR><BR> 2454 * This method may be used regardless of whether the server is listening for 2455 * client connections, and regardless of whether search operations are allowed 2456 * in the server. 2457 */ 2458 @Override() 2459 @NotNull() 2460 public SearchResult search(@NotNull final String baseDN, 2461 @NotNull final SearchScope scope, 2462 @NotNull final Filter filter, 2463 @Nullable final String... attributes) 2464 throws LDAPSearchException 2465 { 2466 return search(new SearchRequest(baseDN, scope, filter, attributes)); 2467 } 2468 2469 2470 2471 /** 2472 * {@inheritDoc} 2473 * <BR><BR> 2474 * This method may be used regardless of whether the server is listening for 2475 * client connections, and regardless of whether search operations are allowed 2476 * in the server. 2477 */ 2478 @Override() 2479 @NotNull() 2480 public SearchResult search( 2481 @Nullable final SearchResultListener searchResultListener, 2482 @NotNull final String baseDN, @NotNull final SearchScope scope, 2483 @NotNull final String filter, 2484 @Nullable final String... attributes) 2485 throws LDAPSearchException 2486 { 2487 return search(new SearchRequest(searchResultListener, baseDN, scope, 2488 parseFilter(filter), attributes)); 2489 } 2490 2491 2492 2493 /** 2494 * {@inheritDoc} 2495 * <BR><BR> 2496 * This method may be used regardless of whether the server is listening for 2497 * client connections, and regardless of whether search operations are allowed 2498 * in the server. 2499 */ 2500 @Override() 2501 @NotNull() 2502 public SearchResult search( 2503 @Nullable final SearchResultListener searchResultListener, 2504 @NotNull final String baseDN, @NotNull final SearchScope scope, 2505 @NotNull final Filter filter, 2506 @Nullable final String... attributes) 2507 throws LDAPSearchException 2508 { 2509 return search(new SearchRequest(searchResultListener, baseDN, scope, 2510 filter, attributes)); 2511 } 2512 2513 2514 2515 /** 2516 * {@inheritDoc} 2517 * <BR><BR> 2518 * This method may be used regardless of whether the server is listening for 2519 * client connections, and regardless of whether search operations are allowed 2520 * in the server. 2521 */ 2522 @Override() 2523 @NotNull() 2524 public SearchResult search(@NotNull final String baseDN, 2525 @NotNull final SearchScope scope, 2526 @NotNull final DereferencePolicy derefPolicy, 2527 final int sizeLimit, final int timeLimit, 2528 final boolean typesOnly, 2529 @NotNull final String filter, 2530 @Nullable final String... attributes) 2531 throws LDAPSearchException 2532 { 2533 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 2534 timeLimit, typesOnly, parseFilter(filter), attributes)); 2535 } 2536 2537 2538 2539 /** 2540 * {@inheritDoc} 2541 * <BR><BR> 2542 * This method may be used regardless of whether the server is listening for 2543 * client connections, and regardless of whether search operations are allowed 2544 * in the server. 2545 */ 2546 @Override() 2547 @NotNull() 2548 public SearchResult search(@NotNull final String baseDN, 2549 @NotNull final SearchScope scope, 2550 @NotNull final DereferencePolicy derefPolicy, 2551 final int sizeLimit, final int timeLimit, 2552 final boolean typesOnly, 2553 @NotNull final Filter filter, 2554 @Nullable final String... attributes) 2555 throws LDAPSearchException 2556 { 2557 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit, 2558 timeLimit, typesOnly, filter, attributes)); 2559 } 2560 2561 2562 2563 /** 2564 * {@inheritDoc} 2565 * <BR><BR> 2566 * This method may be used regardless of whether the server is listening for 2567 * client connections, and regardless of whether search operations are allowed 2568 * in the server. 2569 */ 2570 @Override() 2571 @NotNull() 2572 public SearchResult search( 2573 @Nullable final SearchResultListener searchResultListener, 2574 @NotNull final String baseDN, @NotNull final SearchScope scope, 2575 @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, 2576 final int timeLimit, final boolean typesOnly, 2577 @NotNull final String filter, 2578 @Nullable final String... attributes) 2579 throws LDAPSearchException 2580 { 2581 return search(new SearchRequest(searchResultListener, baseDN, scope, 2582 derefPolicy, sizeLimit, timeLimit, typesOnly, parseFilter(filter), 2583 attributes)); 2584 } 2585 2586 2587 2588 /** 2589 * {@inheritDoc} 2590 * <BR><BR> 2591 * This method may be used regardless of whether the server is listening for 2592 * client connections, and regardless of whether search operations are allowed 2593 * in the server. 2594 */ 2595 @Override() 2596 @NotNull() 2597 public SearchResult search( 2598 @Nullable final SearchResultListener searchResultListener, 2599 @NotNull final String baseDN, @NotNull final SearchScope scope, 2600 @NotNull final DereferencePolicy derefPolicy, final int sizeLimit, 2601 final int timeLimit, final boolean typesOnly, 2602 @NotNull final Filter filter, 2603 @Nullable final String... attributes) 2604 throws LDAPSearchException 2605 { 2606 return search(new SearchRequest(searchResultListener, baseDN, scope, 2607 derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes)); 2608 } 2609 2610 2611 2612 /** 2613 * {@inheritDoc} 2614 * <BR><BR> 2615 * This method may be used regardless of whether the server is listening for 2616 * client connections, and regardless of whether search operations are allowed 2617 * in the server. 2618 */ 2619 @Override() 2620 @NotNull() 2621 public SearchResult search(@NotNull final SearchRequest searchRequest) 2622 throws LDAPSearchException 2623 { 2624 final ArrayList<Control> requestControlList = 2625 new ArrayList<>(searchRequest.getControlList()); 2626 requestControlList.add(new Control( 2627 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false)); 2628 2629 final List<SearchResultEntry> entryList = 2630 new ArrayList<>(10); 2631 final List<SearchResultReference> referenceList = 2632 new ArrayList<>(10); 2633 2634 final LDAPMessage responseMessage = inMemoryHandler.processSearchRequest(1, 2635 new SearchRequestProtocolOp(searchRequest.getBaseDN(), 2636 searchRequest.getScope(), searchRequest.getDereferencePolicy(), 2637 searchRequest.getSizeLimit(), searchRequest.getTimeLimitSeconds(), 2638 searchRequest.typesOnly(), searchRequest.getFilter(), 2639 searchRequest.getAttributeList()), 2640 requestControlList, entryList, referenceList); 2641 2642 2643 final List<SearchResultEntry> returnEntryList; 2644 final List<SearchResultReference> returnReferenceList; 2645 final SearchResultListener searchListener = 2646 searchRequest.getSearchResultListener(); 2647 if (searchListener == null) 2648 { 2649 returnEntryList = Collections.unmodifiableList(entryList); 2650 returnReferenceList = Collections.unmodifiableList(referenceList); 2651 } 2652 else 2653 { 2654 returnEntryList = null; 2655 returnReferenceList = null; 2656 2657 for (final SearchResultEntry e : entryList) 2658 { 2659 searchListener.searchEntryReturned(e); 2660 } 2661 2662 for (final SearchResultReference r : referenceList) 2663 { 2664 searchListener.searchReferenceReturned(r); 2665 } 2666 } 2667 2668 2669 final SearchResultDoneProtocolOp searchDone = 2670 responseMessage.getSearchResultDoneProtocolOp(); 2671 2672 final ResultCode rc = ResultCode.valueOf(searchDone.getResultCode()); 2673 2674 final String[] referralURLs; 2675 final List<String> referralURLList = searchDone.getReferralURLs(); 2676 if ((referralURLList == null) || referralURLList.isEmpty()) 2677 { 2678 referralURLs = StaticUtils.NO_STRINGS; 2679 } 2680 else 2681 { 2682 referralURLs = new String[referralURLList.size()]; 2683 referralURLList.toArray(referralURLs); 2684 } 2685 2686 final Control[] responseControls; 2687 final List<Control> controlList = responseMessage.getControls(); 2688 if ((controlList == null) || controlList.isEmpty()) 2689 { 2690 responseControls = StaticUtils.NO_CONTROLS; 2691 } 2692 else 2693 { 2694 responseControls = new Control[controlList.size()]; 2695 controlList.toArray(responseControls); 2696 } 2697 2698 final SearchResult searchResult =new SearchResult( 2699 responseMessage.getMessageID(), rc, searchDone.getDiagnosticMessage(), 2700 searchDone.getMatchedDN(), referralURLs, returnEntryList, 2701 returnReferenceList, entryList.size(), referenceList.size(), 2702 responseControls); 2703 2704 if (rc == ResultCode.SUCCESS) 2705 { 2706 return searchResult; 2707 } 2708 else 2709 { 2710 throw new LDAPSearchException(searchResult); 2711 } 2712 } 2713 2714 2715 2716 /** 2717 * {@inheritDoc} 2718 * <BR><BR> 2719 * This method may be used regardless of whether the server is listening for 2720 * client connections, and regardless of whether search operations are allowed 2721 * in the server. 2722 */ 2723 @Override() 2724 @NotNull() 2725 public SearchResult search(@NotNull final ReadOnlySearchRequest searchRequest) 2726 throws LDAPSearchException 2727 { 2728 return search(searchRequest.duplicate()); 2729 } 2730 2731 2732 2733 /** 2734 * {@inheritDoc} 2735 * <BR><BR> 2736 * This method may be used regardless of whether the server is listening for 2737 * client connections, and regardless of whether search operations are allowed 2738 * in the server. 2739 */ 2740 @Override() 2741 @Nullable() 2742 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 2743 @NotNull final SearchScope scope, 2744 @NotNull final String filter, 2745 @Nullable final String... attributes) 2746 throws LDAPSearchException 2747 { 2748 return searchForEntry(new SearchRequest(baseDN, scope, parseFilter(filter), 2749 attributes)); 2750 } 2751 2752 2753 2754 /** 2755 * {@inheritDoc} 2756 * <BR><BR> 2757 * This method may be used regardless of whether the server is listening for 2758 * client connections, and regardless of whether search operations are allowed 2759 * in the server. 2760 */ 2761 @Override() 2762 @Nullable() 2763 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 2764 @NotNull final SearchScope scope, 2765 @NotNull final Filter filter, 2766 @Nullable final String... attributes) 2767 throws LDAPSearchException 2768 { 2769 return searchForEntry(new SearchRequest(baseDN, scope, filter, attributes)); 2770 } 2771 2772 2773 2774 /** 2775 * {@inheritDoc} 2776 * <BR><BR> 2777 * This method may be used regardless of whether the server is listening for 2778 * client connections, and regardless of whether search operations are allowed 2779 * in the server. 2780 */ 2781 @Override() 2782 @Nullable() 2783 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 2784 @NotNull final SearchScope scope, 2785 @NotNull final DereferencePolicy derefPolicy, 2786 final int timeLimit, final boolean typesOnly, 2787 @NotNull final String filter, 2788 @Nullable final String... attributes) 2789 throws LDAPSearchException 2790 { 2791 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1, 2792 timeLimit, typesOnly, parseFilter(filter), attributes)); 2793 } 2794 2795 2796 2797 /** 2798 * {@inheritDoc} 2799 * <BR><BR> 2800 * This method may be used regardless of whether the server is listening for 2801 * client connections, and regardless of whether search operations are allowed 2802 * in the server. 2803 */ 2804 @Override() 2805 @Nullable() 2806 public SearchResultEntry searchForEntry(@NotNull final String baseDN, 2807 @NotNull final SearchScope scope, 2808 @NotNull final DereferencePolicy derefPolicy, 2809 final int timeLimit, final boolean typesOnly, 2810 @NotNull final Filter filter, 2811 @Nullable final String... attributes) 2812 throws LDAPSearchException 2813 { 2814 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1, 2815 timeLimit, typesOnly, filter, attributes)); 2816 } 2817 2818 2819 2820 /** 2821 * {@inheritDoc} 2822 * <BR><BR> 2823 * This method may be used regardless of whether the server is listening for 2824 * client connections, and regardless of whether search operations are allowed 2825 * in the server. 2826 */ 2827 @Override() 2828 @Nullable() 2829 public SearchResultEntry searchForEntry( 2830 @NotNull final SearchRequest searchRequest) 2831 throws LDAPSearchException 2832 { 2833 final ArrayList<Control> requestControlList = 2834 new ArrayList<>(searchRequest.getControlList()); 2835 requestControlList.add(new Control( 2836 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false)); 2837 2838 final SearchRequest r; 2839 if ((searchRequest.getSizeLimit() == 1) && 2840 (searchRequest.getSearchResultListener() == null)) 2841 { 2842 r = searchRequest; 2843 } 2844 else 2845 { 2846 r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(), 2847 searchRequest.getDereferencePolicy(), 1, 2848 searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(), 2849 searchRequest.getFilter(), searchRequest.getAttributes()); 2850 2851 r.setFollowReferrals(InternalSDKHelper.followReferralsInternal(r)); 2852 r.setReferralConnector(InternalSDKHelper.getReferralConnectorInternal(r)); 2853 r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null)); 2854 r.setControls(requestControlList); 2855 } 2856 2857 final SearchResult result; 2858 try 2859 { 2860 result = search(r); 2861 } 2862 catch (final LDAPSearchException lse) 2863 { 2864 Debug.debugException(lse); 2865 2866 if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT) 2867 { 2868 return null; 2869 } 2870 2871 throw lse; 2872 } 2873 2874 if (result.getEntryCount() == 0) 2875 { 2876 return null; 2877 } 2878 else 2879 { 2880 return result.getSearchEntries().get(0); 2881 } 2882 } 2883 2884 2885 2886 /** 2887 * {@inheritDoc} 2888 * <BR><BR> 2889 * This method may be used regardless of whether the server is listening for 2890 * client connections, and regardless of whether search operations are allowed 2891 * in the server. 2892 */ 2893 @Override() 2894 @Nullable() 2895 public SearchResultEntry searchForEntry( 2896 @NotNull final ReadOnlySearchRequest searchRequest) 2897 throws LDAPSearchException 2898 { 2899 return searchForEntry(searchRequest.duplicate()); 2900 } 2901 2902 2903 2904 /** 2905 * Retrieves the configured list of password attributes. 2906 * 2907 * @return The configured list of password attributes. 2908 */ 2909 @NotNull() 2910 public List<String> getPasswordAttributes() 2911 { 2912 return inMemoryHandler.getPasswordAttributes(); 2913 } 2914 2915 2916 2917 /** 2918 * Retrieves the primary password encoder that has been configured for the 2919 * server. 2920 * 2921 * @return The primary password encoder that has been configured for the 2922 * server. 2923 */ 2924 @Nullable() 2925 public InMemoryPasswordEncoder getPrimaryPasswordEncoder() 2926 { 2927 return inMemoryHandler.getPrimaryPasswordEncoder(); 2928 } 2929 2930 2931 2932 /** 2933 * Retrieves a list of all password encoders configured for the server. 2934 * 2935 * @return A list of all password encoders configured for the server. 2936 */ 2937 @NotNull() 2938 public List<InMemoryPasswordEncoder> getAllPasswordEncoders() 2939 { 2940 return inMemoryHandler.getAllPasswordEncoders(); 2941 } 2942 2943 2944 2945 /** 2946 * Retrieves a list of the passwords contained in the provided entry. 2947 * 2948 * @param entry The entry from which to obtain the list of 2949 * passwords. It must not be {@code null}. 2950 * @param clearPasswordToMatch An optional clear-text password that should 2951 * match the values that are returned. If this 2952 * is {@code null}, then all passwords contained 2953 * in the provided entry will be returned. If 2954 * this is non-{@code null}, then only passwords 2955 * matching the clear-text password will be 2956 * returned. 2957 * 2958 * @return A list of the passwords contained in the provided entry, 2959 * optionally restricted to those matching the provided clear-text 2960 * password, or an empty list if the entry does not contain any 2961 * passwords. 2962 */ 2963 @NotNull() 2964 public List<InMemoryDirectoryServerPassword> getPasswordsInEntry( 2965 @NotNull final Entry entry, 2966 @Nullable final ASN1OctetString clearPasswordToMatch) 2967 { 2968 return inMemoryHandler.getPasswordsInEntry(entry, clearPasswordToMatch); 2969 } 2970 2971 2972 2973 /** 2974 * Parses the provided string as a search filter. 2975 * 2976 * @param s The string to be parsed. 2977 * 2978 * @return The parsed filter. 2979 * 2980 * @throws LDAPSearchException If the provided string could not be parsed as 2981 * a valid search filter. 2982 */ 2983 @NotNull() 2984 private static Filter parseFilter(@NotNull final String s) 2985 throws LDAPSearchException 2986 { 2987 try 2988 { 2989 return Filter.create(s); 2990 } 2991 catch (final LDAPException le) 2992 { 2993 throw new LDAPSearchException(le); 2994 } 2995 } 2996 2997 2998 2999 /** 3000 * Indicates whether the specified entry exists in the server. 3001 * <BR><BR> 3002 * This method may be used regardless of whether the server is listening for 3003 * client connections. 3004 * 3005 * @param dn The DN of the entry for which to make the determination. 3006 * 3007 * @return {@code true} if the entry exists, or {@code false} if not. 3008 * 3009 * @throws LDAPException If a problem is encountered while trying to 3010 * communicate with the directory server. 3011 */ 3012 public boolean entryExists(@NotNull final String dn) 3013 throws LDAPException 3014 { 3015 return inMemoryHandler.entryExists(dn); 3016 } 3017 3018 3019 3020 /** 3021 * Indicates whether the specified entry exists in the server and matches the 3022 * given filter. 3023 * <BR><BR> 3024 * This method may be used regardless of whether the server is listening for 3025 * client connections. 3026 * 3027 * @param dn The DN of the entry for which to make the determination. 3028 * @param filter The filter the entry is expected to match. 3029 * 3030 * @return {@code true} if the entry exists and matches the specified filter, 3031 * or {@code false} if not. 3032 * 3033 * @throws LDAPException If a problem is encountered while trying to 3034 * communicate with the directory server. 3035 */ 3036 public boolean entryExists(@NotNull final String dn, 3037 @NotNull final String filter) 3038 throws LDAPException 3039 { 3040 return inMemoryHandler.entryExists(dn, filter); 3041 } 3042 3043 3044 3045 /** 3046 * Indicates whether the specified entry exists in the server. This will 3047 * return {@code true} only if the target entry exists and contains all values 3048 * for all attributes of the provided entry. The entry will be allowed to 3049 * have attribute values not included in the provided entry. 3050 * <BR><BR> 3051 * This method may be used regardless of whether the server is listening for 3052 * client connections. 3053 * 3054 * @param entry The entry to compare against the directory server. 3055 * 3056 * @return {@code true} if the entry exists in the server and is a superset 3057 * of the provided entry, or {@code false} if not. 3058 * 3059 * @throws LDAPException If a problem is encountered while trying to 3060 * communicate with the directory server. 3061 */ 3062 public boolean entryExists(@NotNull final Entry entry) 3063 throws LDAPException 3064 { 3065 return inMemoryHandler.entryExists(entry); 3066 } 3067 3068 3069 3070 /** 3071 * Ensures that an entry with the provided DN exists in the directory. 3072 * <BR><BR> 3073 * This method may be used regardless of whether the server is listening for 3074 * client connections. 3075 * 3076 * @param dn The DN of the entry for which to make the determination. 3077 * 3078 * @throws LDAPException If a problem is encountered while trying to 3079 * communicate with the directory server. 3080 * 3081 * @throws AssertionError If the target entry does not exist. 3082 */ 3083 public void assertEntryExists(@NotNull final String dn) 3084 throws LDAPException, AssertionError 3085 { 3086 inMemoryHandler.assertEntryExists(dn); 3087 } 3088 3089 3090 3091 /** 3092 * Ensures that an entry with the provided DN exists in the directory. 3093 * <BR><BR> 3094 * This method may be used regardless of whether the server is listening for 3095 * client connections. 3096 * 3097 * @param dn The DN of the entry for which to make the determination. 3098 * @param filter A filter that the target entry must match. 3099 * 3100 * @throws LDAPException If a problem is encountered while trying to 3101 * communicate with the directory server. 3102 * 3103 * @throws AssertionError If the target entry does not exist or does not 3104 * match the provided filter. 3105 */ 3106 public void assertEntryExists(@NotNull final String dn, 3107 @NotNull final String filter) 3108 throws LDAPException, AssertionError 3109 { 3110 inMemoryHandler.assertEntryExists(dn, filter); 3111 } 3112 3113 3114 3115 /** 3116 * Ensures that an entry exists in the directory with the same DN and all 3117 * attribute values contained in the provided entry. The server entry may 3118 * contain additional attributes and/or attribute values not included in the 3119 * provided entry. 3120 * <BR><BR> 3121 * This method may be used regardless of whether the server is listening for 3122 * client connections. 3123 * 3124 * @param entry The entry expected to be present in the directory server. 3125 * 3126 * @throws LDAPException If a problem is encountered while trying to 3127 * communicate with the directory server. 3128 * 3129 * @throws AssertionError If the target entry does not exist or does not 3130 * match the provided filter. 3131 */ 3132 public void assertEntryExists(@NotNull final Entry entry) 3133 throws LDAPException, AssertionError 3134 { 3135 inMemoryHandler.assertEntryExists(entry); 3136 } 3137 3138 3139 3140 /** 3141 * Retrieves a list containing the DNs of the entries which are missing from 3142 * the directory server. 3143 * <BR><BR> 3144 * This method may be used regardless of whether the server is listening for 3145 * client connections. 3146 * 3147 * @param dns The DNs of the entries to try to find in the server. 3148 * 3149 * @return A list containing all of the provided DNs that were not found in 3150 * the server, or an empty list if all entries were found. 3151 * 3152 * @throws LDAPException If a problem is encountered while trying to 3153 * communicate with the directory server. 3154 */ 3155 @NotNull() 3156 public List<String> getMissingEntryDNs(@NotNull final String... dns) 3157 throws LDAPException 3158 { 3159 return inMemoryHandler.getMissingEntryDNs(StaticUtils.toList(dns)); 3160 } 3161 3162 3163 3164 /** 3165 * Retrieves a list containing the DNs of the entries which are missing from 3166 * the directory server. 3167 * <BR><BR> 3168 * This method may be used regardless of whether the server is listening for 3169 * client connections. 3170 * 3171 * @param dns The DNs of the entries to try to find in the server. 3172 * 3173 * @return A list containing all of the provided DNs that were not found in 3174 * the server, or an empty list if all entries were found. 3175 * 3176 * @throws LDAPException If a problem is encountered while trying to 3177 * communicate with the directory server. 3178 */ 3179 @NotNull() 3180 public List<String> getMissingEntryDNs(@NotNull final Collection<String> dns) 3181 throws LDAPException 3182 { 3183 return inMemoryHandler.getMissingEntryDNs(dns); 3184 } 3185 3186 3187 3188 /** 3189 * Ensures that all of the entries with the provided DNs exist in the 3190 * directory. 3191 * <BR><BR> 3192 * This method may be used regardless of whether the server is listening for 3193 * client connections. 3194 * 3195 * @param dns The DNs of the entries for which to make the determination. 3196 * 3197 * @throws LDAPException If a problem is encountered while trying to 3198 * communicate with the directory server. 3199 * 3200 * @throws AssertionError If any of the target entries does not exist. 3201 */ 3202 public void assertEntriesExist(@NotNull final String... dns) 3203 throws LDAPException, AssertionError 3204 { 3205 inMemoryHandler.assertEntriesExist(StaticUtils.toList(dns)); 3206 } 3207 3208 3209 3210 /** 3211 * Ensures that all of the entries with the provided DNs exist in the 3212 * directory. 3213 * <BR><BR> 3214 * This method may be used regardless of whether the server is listening for 3215 * client connections. 3216 * 3217 * @param dns The DNs of the entries for which to make the determination. 3218 * 3219 * @throws LDAPException If a problem is encountered while trying to 3220 * communicate with the directory server. 3221 * 3222 * @throws AssertionError If any of the target entries does not exist. 3223 */ 3224 public void assertEntriesExist(@NotNull final Collection<String> dns) 3225 throws LDAPException, AssertionError 3226 { 3227 inMemoryHandler.assertEntriesExist(dns); 3228 } 3229 3230 3231 3232 /** 3233 * Retrieves a list containing all of the named attributes which do not exist 3234 * in the target entry. 3235 * <BR><BR> 3236 * This method may be used regardless of whether the server is listening for 3237 * client connections. 3238 * 3239 * @param dn The DN of the entry to examine. 3240 * @param attributeNames The names of the attributes expected to be present 3241 * in the target entry. 3242 * 3243 * @return A list containing the names of the attributes which were not 3244 * present in the target entry, an empty list if all specified 3245 * attributes were found in the entry, or {@code null} if the target 3246 * entry does not exist. 3247 * 3248 * @throws LDAPException If a problem is encountered while trying to 3249 * communicate with the directory server. 3250 */ 3251 @Nullable() 3252 public List<String> getMissingAttributeNames(@NotNull final String dn, 3253 @NotNull final String... attributeNames) 3254 throws LDAPException 3255 { 3256 return inMemoryHandler.getMissingAttributeNames(dn, 3257 StaticUtils.toList(attributeNames)); 3258 } 3259 3260 3261 3262 /** 3263 * Retrieves a list containing all of the named attributes which do not exist 3264 * in the target entry. 3265 * <BR><BR> 3266 * This method may be used regardless of whether the server is listening for 3267 * client connections. 3268 * 3269 * @param dn The DN of the entry to examine. 3270 * @param attributeNames The names of the attributes expected to be present 3271 * in the target entry. 3272 * 3273 * @return A list containing the names of the attributes which were not 3274 * present in the target entry, an empty list if all specified 3275 * attributes were found in the entry, or {@code null} if the target 3276 * entry does not exist. 3277 * 3278 * @throws LDAPException If a problem is encountered while trying to 3279 * communicate with the directory server. 3280 */ 3281 @Nullable() 3282 public List<String> getMissingAttributeNames(@NotNull final String dn, 3283 @NotNull final Collection<String> attributeNames) 3284 throws LDAPException 3285 { 3286 return inMemoryHandler.getMissingAttributeNames(dn, attributeNames); 3287 } 3288 3289 3290 3291 /** 3292 * Ensures that the specified entry exists in the directory with all of the 3293 * specified attributes. 3294 * <BR><BR> 3295 * This method may be used regardless of whether the server is listening for 3296 * client connections. 3297 * 3298 * @param dn The DN of the entry to examine. 3299 * @param attributeNames The names of the attributes that are expected to be 3300 * present in the provided entry. 3301 * 3302 * @throws LDAPException If a problem is encountered while trying to 3303 * communicate with the directory server. 3304 * 3305 * @throws AssertionError If the target entry does not exist or does not 3306 * contain all of the specified attributes. 3307 */ 3308 public void assertAttributeExists(@NotNull final String dn, 3309 @NotNull final String... attributeNames) 3310 throws LDAPException, AssertionError 3311 { 3312 inMemoryHandler.assertAttributeExists(dn, 3313 StaticUtils.toList(attributeNames)); 3314 } 3315 3316 3317 3318 /** 3319 * Ensures that the specified entry exists in the directory with all of the 3320 * specified attributes. 3321 * <BR><BR> 3322 * This method may be used regardless of whether the server is listening for 3323 * client connections. 3324 * 3325 * @param dn The DN of the entry to examine. 3326 * @param attributeNames The names of the attributes that are expected to be 3327 * present in the provided entry. 3328 * 3329 * @throws LDAPException If a problem is encountered while trying to 3330 * communicate with the directory server. 3331 * 3332 * @throws AssertionError If the target entry does not exist or does not 3333 * contain all of the specified attributes. 3334 */ 3335 public void assertAttributeExists(@NotNull final String dn, 3336 @NotNull final Collection<String> attributeNames) 3337 throws LDAPException, AssertionError 3338 { 3339 inMemoryHandler.assertAttributeExists(dn, attributeNames); 3340 } 3341 3342 3343 3344 /** 3345 * Retrieves a list of all provided attribute values which are missing from 3346 * the specified entry. 3347 * <BR><BR> 3348 * This method may be used regardless of whether the server is listening for 3349 * client connections. 3350 * 3351 * @param dn The DN of the entry to examine. 3352 * @param attributeName The attribute expected to be present in the target 3353 * entry with the given values. 3354 * @param attributeValues The values expected to be present in the target 3355 * entry. 3356 * 3357 * @return A list containing all of the provided values which were not found 3358 * in the entry, an empty list if all provided attribute values were 3359 * found, or {@code null} if the target entry does not exist. 3360 * 3361 * @throws LDAPException If a problem is encountered while trying to 3362 * communicate with the directory server. 3363 */ 3364 @Nullable() 3365 public List<String> getMissingAttributeValues(@NotNull final String dn, 3366 @NotNull final String attributeName, 3367 @NotNull final String... attributeValues) 3368 throws LDAPException 3369 { 3370 return inMemoryHandler.getMissingAttributeValues(dn, attributeName, 3371 StaticUtils.toList(attributeValues)); 3372 } 3373 3374 3375 3376 /** 3377 * Retrieves a list of all provided attribute values which are missing from 3378 * the specified entry. The target attribute may or may not contain 3379 * additional values. 3380 * <BR><BR> 3381 * This method may be used regardless of whether the server is listening for 3382 * client connections. 3383 * 3384 * @param dn The DN of the entry to examine. 3385 * @param attributeName The attribute expected to be present in the target 3386 * entry with the given values. 3387 * @param attributeValues The values expected to be present in the target 3388 * entry. 3389 * 3390 * @return A list containing all of the provided values which were not found 3391 * in the entry, an empty list if all provided attribute values were 3392 * found, or {@code null} if the target entry does not exist. 3393 * 3394 * @throws LDAPException If a problem is encountered while trying to 3395 * communicate with the directory server. 3396 */ 3397 @Nullable() 3398 public List<String> getMissingAttributeValues(@NotNull final String dn, 3399 @NotNull final String attributeName, 3400 @NotNull final Collection<String> attributeValues) 3401 throws LDAPException 3402 { 3403 return inMemoryHandler.getMissingAttributeValues(dn, attributeName, 3404 attributeValues); 3405 } 3406 3407 3408 3409 /** 3410 * Ensures that the specified entry exists in the directory with all of the 3411 * specified values for the given attribute. The attribute may or may not 3412 * contain additional values. 3413 * <BR><BR> 3414 * This method may be used regardless of whether the server is listening for 3415 * client connections. 3416 * 3417 * @param dn The DN of the entry to examine. 3418 * @param attributeName The name of the attribute to examine. 3419 * @param attributeValues The set of values which must exist for the given 3420 * attribute. 3421 * 3422 * @throws LDAPException If a problem is encountered while trying to 3423 * communicate with the directory server. 3424 * 3425 * @throws AssertionError If the target entry does not exist, does not 3426 * contain the specified attribute, or that attribute 3427 * does not have all of the specified values. 3428 */ 3429 public void assertValueExists(@NotNull final String dn, 3430 @NotNull final String attributeName, 3431 @NotNull final String... attributeValues) 3432 throws LDAPException, AssertionError 3433 { 3434 inMemoryHandler.assertValueExists(dn, attributeName, 3435 StaticUtils.toList(attributeValues)); 3436 } 3437 3438 3439 3440 /** 3441 * Ensures that the specified entry exists in the directory with all of the 3442 * specified values for the given attribute. The attribute may or may not 3443 * contain additional values. 3444 * <BR><BR> 3445 * This method may be used regardless of whether the server is listening for 3446 * client connections. 3447 * 3448 * @param dn The DN of the entry to examine. 3449 * @param attributeName The name of the attribute to examine. 3450 * @param attributeValues The set of values which must exist for the given 3451 * attribute. 3452 * 3453 * @throws LDAPException If a problem is encountered while trying to 3454 * communicate with the directory server. 3455 * 3456 * @throws AssertionError If the target entry does not exist, does not 3457 * contain the specified attribute, or that attribute 3458 * does not have all of the specified values. 3459 */ 3460 public void assertValueExists(@NotNull final String dn, 3461 @NotNull final String attributeName, 3462 @NotNull final Collection<String> attributeValues) 3463 throws LDAPException, AssertionError 3464 { 3465 inMemoryHandler.assertValueExists(dn, attributeName, attributeValues); 3466 } 3467 3468 3469 3470 /** 3471 * Ensures that the specified entry does not exist in the directory. 3472 * <BR><BR> 3473 * This method may be used regardless of whether the server is listening for 3474 * client connections. 3475 * 3476 * @param dn The DN of the entry expected to be missing. 3477 * 3478 * @throws LDAPException If a problem is encountered while trying to 3479 * communicate with the directory server. 3480 * 3481 * @throws AssertionError If the target entry is found in the server. 3482 */ 3483 public void assertEntryMissing(@NotNull final String dn) 3484 throws LDAPException, AssertionError 3485 { 3486 inMemoryHandler.assertEntryMissing(dn); 3487 } 3488 3489 3490 3491 /** 3492 * Ensures that the specified entry exists in the directory but does not 3493 * contain any of the specified attributes. 3494 * <BR><BR> 3495 * This method may be used regardless of whether the server is listening for 3496 * client connections. 3497 * 3498 * @param dn The DN of the entry expected to be present. 3499 * @param attributeNames The names of the attributes expected to be missing 3500 * from the entry. 3501 * 3502 * @throws LDAPException If a problem is encountered while trying to 3503 * communicate with the directory server. 3504 * 3505 * @throws AssertionError If the target entry is missing from the server, or 3506 * if it contains any of the target attributes. 3507 */ 3508 public void assertAttributeMissing(@NotNull final String dn, 3509 @NotNull final String... attributeNames) 3510 throws LDAPException, AssertionError 3511 { 3512 inMemoryHandler.assertAttributeMissing(dn, 3513 StaticUtils.toList(attributeNames)); 3514 } 3515 3516 3517 3518 /** 3519 * Ensures that the specified entry exists in the directory but does not 3520 * contain any of the specified attributes. 3521 * <BR><BR> 3522 * This method may be used regardless of whether the server is listening for 3523 * client connections. 3524 * 3525 * @param dn The DN of the entry expected to be present. 3526 * @param attributeNames The names of the attributes expected to be missing 3527 * from the entry. 3528 * 3529 * @throws LDAPException If a problem is encountered while trying to 3530 * communicate with the directory server. 3531 * 3532 * @throws AssertionError If the target entry is missing from the server, or 3533 * if it contains any of the target attributes. 3534 */ 3535 public void assertAttributeMissing(@NotNull final String dn, 3536 @NotNull final Collection<String> attributeNames) 3537 throws LDAPException, AssertionError 3538 { 3539 inMemoryHandler.assertAttributeMissing(dn, attributeNames); 3540 } 3541 3542 3543 3544 /** 3545 * Ensures that the specified entry exists in the directory but does not 3546 * contain any of the specified attribute values. 3547 * <BR><BR> 3548 * This method may be used regardless of whether the server is listening for 3549 * client connections. 3550 * 3551 * @param dn The DN of the entry expected to be present. 3552 * @param attributeName The name of the attribute to examine. 3553 * @param attributeValues The values expected to be missing from the target 3554 * entry. 3555 * 3556 * @throws LDAPException If a problem is encountered while trying to 3557 * communicate with the directory server. 3558 * 3559 * @throws AssertionError If the target entry is missing from the server, or 3560 * if it contains any of the target attribute values. 3561 */ 3562 public void assertValueMissing(@NotNull final String dn, 3563 @NotNull final String attributeName, 3564 @NotNull final String... attributeValues) 3565 throws LDAPException, AssertionError 3566 { 3567 inMemoryHandler.assertValueMissing(dn, attributeName, 3568 StaticUtils.toList(attributeValues)); 3569 } 3570 3571 3572 3573 /** 3574 * Ensures that the specified entry exists in the directory but does not 3575 * contain any of the specified attribute values. 3576 * <BR><BR> 3577 * This method may be used regardless of whether the server is listening for 3578 * client connections. 3579 * 3580 * @param dn The DN of the entry expected to be present. 3581 * @param attributeName The name of the attribute to examine. 3582 * @param attributeValues The values expected to be missing from the target 3583 * entry. 3584 * 3585 * @throws LDAPException If a problem is encountered while trying to 3586 * communicate with the directory server. 3587 * 3588 * @throws AssertionError If the target entry is missing from the server, or 3589 * if it contains any of the target attribute values. 3590 */ 3591 public void assertValueMissing(@NotNull final String dn, 3592 @NotNull final String attributeName, 3593 @NotNull final Collection<String> attributeValues) 3594 throws LDAPException, AssertionError 3595 { 3596 inMemoryHandler.assertValueMissing(dn, attributeName, attributeValues); 3597 } 3598}