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