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