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