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