001/* 002 * Copyright 2007-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-2022 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2007-2022 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk; 037 038 039 040import java.util.List; 041import java.util.Timer; 042import java.util.concurrent.LinkedBlockingQueue; 043import java.util.concurrent.TimeUnit; 044import java.util.logging.Level; 045 046import com.unboundid.asn1.ASN1Buffer; 047import com.unboundid.asn1.ASN1Element; 048import com.unboundid.asn1.ASN1OctetString; 049import com.unboundid.ldap.protocol.LDAPMessage; 050import com.unboundid.ldap.protocol.LDAPResponse; 051import com.unboundid.ldap.protocol.ProtocolOp; 052import com.unboundid.ldif.LDIFDeleteChangeRecord; 053import com.unboundid.util.Debug; 054import com.unboundid.util.InternalUseOnly; 055import com.unboundid.util.Mutable; 056import com.unboundid.util.NotNull; 057import com.unboundid.util.Nullable; 058import com.unboundid.util.StaticUtils; 059import com.unboundid.util.ThreadSafety; 060import com.unboundid.util.ThreadSafetyLevel; 061import com.unboundid.util.Validator; 062 063import static com.unboundid.ldap.sdk.LDAPMessages.*; 064 065 066 067/** 068 * This class implements the processing necessary to perform an LDAPv3 delete 069 * operation, which removes an entry from the directory. A delete request 070 * contains the DN of the entry to remove. It may also include a set of 071 * controls to send to the server. 072 * {@code DeleteRequest} objects are mutable and therefore can be altered and 073 * re-used for multiple requests. Note, however, that {@code DeleteRequest} 074 * objects are not threadsafe and therefore a single {@code DeleteRequest} 075 * object instance should not be used to process multiple requests at the same 076 * time. 077 * <BR><BR> 078 * <H2>Example</H2> 079 * The following example demonstrates the process for performing a delete 080 * operation: 081 * <PRE> 082 * DeleteRequest deleteRequest = 083 * new DeleteRequest("cn=entry to delete,dc=example,dc=com"); 084 * LDAPResult deleteResult; 085 * try 086 * { 087 * deleteResult = connection.delete(deleteRequest); 088 * // If we get here, the delete was successful. 089 * } 090 * catch (LDAPException le) 091 * { 092 * // The delete operation failed. 093 * deleteResult = le.toLDAPResult(); 094 * ResultCode resultCode = le.getResultCode(); 095 * String errorMessageFromServer = le.getDiagnosticMessage(); 096 * } 097 * </PRE> 098 */ 099@Mutable() 100@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 101public final class DeleteRequest 102 extends UpdatableLDAPRequest 103 implements ReadOnlyDeleteRequest, ResponseAcceptor, ProtocolOp 104{ 105 /** 106 * The serial version UID for this serializable class. 107 */ 108 private static final long serialVersionUID = -6126029442850884239L; 109 110 111 112 // The message ID from the last LDAP message sent from this request. 113 private int messageID = -1; 114 115 // The queue that will be used to receive response messages from the server. 116 @NotNull private final LinkedBlockingQueue<LDAPResponse> responseQueue = 117 new LinkedBlockingQueue<>(); 118 119 // The DN of the entry to delete. 120 @NotNull private String dn; 121 122 123 124 /** 125 * Creates a new delete request with the provided DN. 126 * 127 * @param dn The DN of the entry to delete. It must not be {@code null}. 128 */ 129 public DeleteRequest(@NotNull final String dn) 130 { 131 super(null); 132 133 Validator.ensureNotNull(dn); 134 135 this.dn = dn; 136 } 137 138 139 140 /** 141 * Creates a new delete request with the provided DN. 142 * 143 * @param dn The DN of the entry to delete. It must not be 144 * {@code null}. 145 * @param controls The set of controls to include in the request. 146 */ 147 public DeleteRequest(@NotNull final String dn, 148 @Nullable final Control[] controls) 149 { 150 super(controls); 151 152 Validator.ensureNotNull(dn); 153 154 this.dn = dn; 155 } 156 157 158 159 /** 160 * Creates a new delete request with the provided DN. 161 * 162 * @param dn The DN of the entry to delete. It must not be {@code null}. 163 */ 164 public DeleteRequest(@NotNull final DN dn) 165 { 166 super(null); 167 168 Validator.ensureNotNull(dn); 169 170 this.dn = dn.toString(); 171 } 172 173 174 175 /** 176 * Creates a new delete request with the provided DN. 177 * 178 * @param dn The DN of the entry to delete. It must not be 179 * {@code null}. 180 * @param controls The set of controls to include in the request. 181 */ 182 public DeleteRequest(@NotNull final DN dn, 183 @Nullable final Control[] controls) 184 { 185 super(controls); 186 187 Validator.ensureNotNull(dn); 188 189 this.dn = dn.toString(); 190 } 191 192 193 194 /** 195 * {@inheritDoc} 196 */ 197 @Override() 198 @NotNull() 199 public String getDN() 200 { 201 return dn; 202 } 203 204 205 206 /** 207 * Specifies the DN of the entry to delete. 208 * 209 * @param dn The DN of the entry to delete. It must not be {@code null}. 210 */ 211 public void setDN(@NotNull final String dn) 212 { 213 Validator.ensureNotNull(dn); 214 215 this.dn = dn; 216 } 217 218 219 220 /** 221 * Specifies the DN of the entry to delete. 222 * 223 * @param dn The DN of the entry to delete. It must not be {@code null}. 224 */ 225 public void setDN(@NotNull final DN dn) 226 { 227 Validator.ensureNotNull(dn); 228 229 this.dn = dn.toString(); 230 } 231 232 233 234 /** 235 * {@inheritDoc} 236 */ 237 @Override() 238 public byte getProtocolOpType() 239 { 240 return LDAPMessage.PROTOCOL_OP_TYPE_DELETE_REQUEST; 241 } 242 243 244 245 /** 246 * {@inheritDoc} 247 */ 248 @Override() 249 public void writeTo(@NotNull final ASN1Buffer buffer) 250 { 251 buffer.addOctetString(LDAPMessage.PROTOCOL_OP_TYPE_DELETE_REQUEST, dn); 252 } 253 254 255 256 /** 257 * Encodes the delete request protocol op to an ASN.1 element. 258 * 259 * @return The ASN.1 element with the encoded delete request protocol op. 260 */ 261 @Override() 262 @NotNull() 263 public ASN1Element encodeProtocolOp() 264 { 265 return new ASN1OctetString(LDAPMessage.PROTOCOL_OP_TYPE_DELETE_REQUEST, dn); 266 } 267 268 269 270 /** 271 * Sends this delete request to the directory server over the provided 272 * connection and returns the associated response. 273 * 274 * @param connection The connection to use to communicate with the directory 275 * server. 276 * @param depth The current referral depth for this request. It should 277 * always be one for the initial request, and should only 278 * be incremented when following referrals. 279 * 280 * @return An LDAP result object that provides information about the result 281 * of the delete processing. 282 * 283 * @throws LDAPException If a problem occurs while sending the request or 284 * reading the response. 285 */ 286 @Override() 287 @NotNull() 288 protected LDAPResult process(@NotNull final LDAPConnection connection, 289 final int depth) 290 throws LDAPException 291 { 292 if (connection.synchronousMode()) 293 { 294 @SuppressWarnings("deprecation") 295 final boolean autoReconnect = 296 connection.getConnectionOptions().autoReconnect(); 297 return processSync(connection, depth, autoReconnect); 298 } 299 300 final long requestTime = System.nanoTime(); 301 processAsync(connection, null); 302 303 try 304 { 305 // Wait for and process the response. 306 final LDAPResponse response; 307 try 308 { 309 final long responseTimeout = getResponseTimeoutMillis(connection); 310 if (responseTimeout > 0) 311 { 312 response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS); 313 } 314 else 315 { 316 response = responseQueue.take(); 317 } 318 } 319 catch (final InterruptedException ie) 320 { 321 Debug.debugException(ie); 322 Thread.currentThread().interrupt(); 323 throw new LDAPException(ResultCode.LOCAL_ERROR, 324 ERR_DELETE_INTERRUPTED.get(connection.getHostPort()), ie); 325 } 326 327 return handleResponse(connection, response, requestTime, depth, false); 328 } 329 finally 330 { 331 connection.deregisterResponseAcceptor(messageID); 332 } 333 } 334 335 336 337 /** 338 * Sends this delete request to the directory server over the provided 339 * connection and returns the message ID for the request. 340 * 341 * @param connection The connection to use to communicate with the 342 * directory server. 343 * @param resultListener The async result listener that is to be notified 344 * when the response is received. It may be 345 * {@code null} only if the result is to be processed 346 * by this class. 347 * 348 * @return The async request ID created for the operation, or {@code null} if 349 * the provided {@code resultListener} is {@code null} and the 350 * operation will not actually be processed asynchronously. 351 * 352 * @throws LDAPException If a problem occurs while sending the request. 353 */ 354 @Nullable() 355 AsyncRequestID processAsync(@NotNull final LDAPConnection connection, 356 @Nullable final AsyncResultListener resultListener) 357 throws LDAPException 358 { 359 // Create the LDAP message. 360 messageID = connection.nextMessageID(); 361 final LDAPMessage message = new LDAPMessage(messageID, this, getControls()); 362 363 364 // If the provided async result listener is {@code null}, then we'll use 365 // this class as the message acceptor. Otherwise, create an async helper 366 // and use it as the message acceptor. 367 final AsyncRequestID asyncRequestID; 368 final long timeout = getResponseTimeoutMillis(connection); 369 if (resultListener == null) 370 { 371 asyncRequestID = null; 372 connection.registerResponseAcceptor(messageID, this); 373 } 374 else 375 { 376 final AsyncHelper helper = new AsyncHelper(connection, 377 OperationType.DELETE, messageID, resultListener, 378 getIntermediateResponseListener()); 379 connection.registerResponseAcceptor(messageID, helper); 380 asyncRequestID = helper.getAsyncRequestID(); 381 382 if (timeout > 0L) 383 { 384 final Timer timer = connection.getTimer(); 385 final AsyncTimeoutTimerTask timerTask = 386 new AsyncTimeoutTimerTask(helper); 387 timer.schedule(timerTask, timeout); 388 asyncRequestID.setTimerTask(timerTask); 389 } 390 } 391 392 393 // Send the request to the server. 394 try 395 { 396 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 397 398 final LDAPConnectionLogger logger = 399 connection.getConnectionOptions().getConnectionLogger(); 400 if (logger != null) 401 { 402 logger.logDeleteRequest(connection, messageID, this); 403 } 404 405 connection.getConnectionStatistics().incrementNumDeleteRequests(); 406 connection.sendMessage(message, timeout); 407 return asyncRequestID; 408 } 409 catch (final LDAPException le) 410 { 411 Debug.debugException(le); 412 413 connection.deregisterResponseAcceptor(messageID); 414 throw le; 415 } 416 } 417 418 419 420 /** 421 * Processes this delete operation in synchronous mode, in which the same 422 * thread will send the request and read the response. 423 * 424 * @param connection The connection to use to communicate with the directory 425 * server. 426 * @param depth The current referral depth for this request. It should 427 * always be one for the initial request, and should only 428 * be incremented when following referrals. 429 * @param allowRetry Indicates whether the request may be re-tried on a 430 * re-established connection if the initial attempt fails 431 * in a way that indicates the connection is no longer 432 * valid and autoReconnect is true. 433 * 434 * @return An LDAP result object that provides information about the result 435 * of the delete processing. 436 * 437 * @throws LDAPException If a problem occurs while sending the request or 438 * reading the response. 439 */ 440 @NotNull() 441 private LDAPResult processSync(@NotNull final LDAPConnection connection, 442 final int depth, final boolean allowRetry) 443 throws LDAPException 444 { 445 // Create the LDAP message. 446 messageID = connection.nextMessageID(); 447 final LDAPMessage message = 448 new LDAPMessage(messageID, this, getControls()); 449 450 451 // Send the request to the server. 452 final long requestTime = System.nanoTime(); 453 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 454 455 final LDAPConnectionLogger logger = 456 connection.getConnectionOptions().getConnectionLogger(); 457 if (logger != null) 458 { 459 logger.logDeleteRequest(connection, messageID, this); 460 } 461 462 connection.getConnectionStatistics().incrementNumDeleteRequests(); 463 try 464 { 465 connection.sendMessage(message, getResponseTimeoutMillis(connection)); 466 } 467 catch (final LDAPException le) 468 { 469 Debug.debugException(le); 470 471 if (allowRetry) 472 { 473 final LDAPResult retryResult = reconnectAndRetry(connection, depth, 474 le.getResultCode()); 475 if (retryResult != null) 476 { 477 return retryResult; 478 } 479 } 480 481 throw le; 482 } 483 484 while (true) 485 { 486 final LDAPResponse response; 487 try 488 { 489 response = connection.readResponse(messageID); 490 } 491 catch (final LDAPException le) 492 { 493 Debug.debugException(le); 494 495 if ((le.getResultCode() == ResultCode.TIMEOUT) && 496 connection.getConnectionOptions().abandonOnTimeout()) 497 { 498 connection.abandon(messageID); 499 } 500 501 if (allowRetry) 502 { 503 final LDAPResult retryResult = reconnectAndRetry(connection, depth, 504 le.getResultCode()); 505 if (retryResult != null) 506 { 507 return retryResult; 508 } 509 } 510 511 throw le; 512 } 513 514 if (response instanceof IntermediateResponse) 515 { 516 final IntermediateResponseListener listener = 517 getIntermediateResponseListener(); 518 if (listener != null) 519 { 520 listener.intermediateResponseReturned( 521 (IntermediateResponse) response); 522 } 523 } 524 else 525 { 526 return handleResponse(connection, response, requestTime, depth, 527 allowRetry); 528 } 529 } 530 } 531 532 533 534 /** 535 * Performs the necessary processing for handling a response. 536 * 537 * @param connection The connection used to read the response. 538 * @param response The response to be processed. 539 * @param requestTime The time the request was sent to the server. 540 * @param depth The current referral depth for this request. It 541 * should always be one for the initial request, and 542 * should only be incremented when following referrals. 543 * @param allowRetry Indicates whether the request may be re-tried on a 544 * re-established connection if the initial attempt fails 545 * in a way that indicates the connection is no longer 546 * valid and autoReconnect is true. 547 * 548 * @return The delete result. 549 * 550 * @throws LDAPException If a problem occurs. 551 */ 552 @NotNull() 553 private LDAPResult handleResponse(@NotNull final LDAPConnection connection, 554 @Nullable final LDAPResponse response, 555 final long requestTime, final int depth, 556 final boolean allowRetry) 557 throws LDAPException 558 { 559 if (response == null) 560 { 561 final long waitTime = 562 StaticUtils.nanosToMillis(System.nanoTime() - requestTime); 563 if (connection.getConnectionOptions().abandonOnTimeout()) 564 { 565 connection.abandon(messageID); 566 } 567 568 throw new LDAPException(ResultCode.TIMEOUT, 569 ERR_DELETE_CLIENT_TIMEOUT.get(waitTime, messageID, dn, 570 connection.getHostPort())); 571 } 572 573 connection.getConnectionStatistics().incrementNumDeleteResponses( 574 System.nanoTime() - requestTime); 575 if (response instanceof ConnectionClosedResponse) 576 { 577 // The connection was closed while waiting for the response. 578 if (allowRetry) 579 { 580 final LDAPResult retryResult = reconnectAndRetry(connection, depth, 581 ResultCode.SERVER_DOWN); 582 if (retryResult != null) 583 { 584 return retryResult; 585 } 586 } 587 588 final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response; 589 final String message = ccr.getMessage(); 590 if (message == null) 591 { 592 throw new LDAPException(ccr.getResultCode(), 593 ERR_CONN_CLOSED_WAITING_FOR_DELETE_RESPONSE.get( 594 connection.getHostPort(), toString())); 595 } 596 else 597 { 598 throw new LDAPException(ccr.getResultCode(), 599 ERR_CONN_CLOSED_WAITING_FOR_DELETE_RESPONSE_WITH_MESSAGE.get( 600 connection.getHostPort(), toString(), message)); 601 } 602 } 603 604 final LDAPResult result = (LDAPResult) response; 605 if ((result.getResultCode().equals(ResultCode.REFERRAL)) && 606 followReferrals(connection)) 607 { 608 if (depth >= connection.getConnectionOptions().getReferralHopLimit()) 609 { 610 return new LDAPResult(messageID, ResultCode.REFERRAL_LIMIT_EXCEEDED, 611 ERR_TOO_MANY_REFERRALS.get(), 612 result.getMatchedDN(), result.getReferralURLs(), 613 result.getResponseControls()); 614 } 615 616 return followReferral(result, connection, depth); 617 } 618 else 619 { 620 if (allowRetry) 621 { 622 final LDAPResult retryResult = reconnectAndRetry(connection, depth, 623 result.getResultCode()); 624 if (retryResult != null) 625 { 626 return retryResult; 627 } 628 } 629 630 return result; 631 } 632 } 633 634 635 636 /** 637 * Attempts to re-establish the connection and retry processing this request 638 * on it. 639 * 640 * @param connection The connection to be re-established. 641 * @param depth The current referral depth for this request. It should 642 * always be one for the initial request, and should only 643 * be incremented when following referrals. 644 * @param resultCode The result code for the previous operation attempt. 645 * 646 * @return The result from re-trying the add, or {@code null} if it could not 647 * be re-tried. 648 */ 649 @Nullable() 650 private LDAPResult reconnectAndRetry(@NotNull final LDAPConnection connection, 651 final int depth, 652 @NotNull final ResultCode resultCode) 653 { 654 try 655 { 656 // We will only want to retry for certain result codes that indicate a 657 // connection problem. 658 switch (resultCode.intValue()) 659 { 660 case ResultCode.SERVER_DOWN_INT_VALUE: 661 case ResultCode.DECODING_ERROR_INT_VALUE: 662 case ResultCode.CONNECT_ERROR_INT_VALUE: 663 connection.reconnect(); 664 return processSync(connection, depth, false); 665 } 666 } 667 catch (final Exception e) 668 { 669 Debug.debugException(e); 670 } 671 672 return null; 673 } 674 675 676 677 /** 678 * Attempts to follow a referral to perform a delete operation in the target 679 * server. 680 * 681 * @param referralResult The LDAP result object containing information about 682 * the referral to follow. 683 * @param connection The connection on which the referral was received. 684 * @param depth The number of referrals followed in the course of 685 * processing this request. 686 * 687 * @return The result of attempting to process the delete operation by 688 * following the referral. 689 * 690 * @throws LDAPException If a problem occurs while attempting to establish 691 * the referral connection, sending the request, or 692 * reading the result. 693 */ 694 @NotNull() 695 private LDAPResult followReferral(@NotNull final LDAPResult referralResult, 696 @NotNull final LDAPConnection connection, 697 final int depth) 698 throws LDAPException 699 { 700 for (final String urlString : referralResult.getReferralURLs()) 701 { 702 try 703 { 704 final LDAPURL referralURL = new LDAPURL(urlString); 705 final String host = referralURL.getHost(); 706 707 if (host == null) 708 { 709 // We can't handle a referral in which there is no host. 710 continue; 711 } 712 713 final DeleteRequest deleteRequest; 714 if (referralURL.baseDNProvided()) 715 { 716 deleteRequest = new DeleteRequest(referralURL.getBaseDN(), 717 getControls()); 718 } 719 else 720 { 721 deleteRequest = this; 722 } 723 724 final LDAPConnection referralConn = getReferralConnector(connection). 725 getReferralConnection(referralURL, connection); 726 try 727 { 728 return deleteRequest.process(referralConn, depth+1); 729 } 730 finally 731 { 732 referralConn.setDisconnectInfo(DisconnectType.REFERRAL, null, null); 733 referralConn.close(); 734 } 735 } 736 catch (final LDAPException le) 737 { 738 Debug.debugException(le); 739 } 740 } 741 742 // If we've gotten here, then we could not follow any of the referral URLs, 743 // so we'll just return the original referral result. 744 return referralResult; 745 } 746 747 748 749 /** 750 * {@inheritDoc} 751 */ 752 @InternalUseOnly() 753 @Override() 754 public void responseReceived(@NotNull final LDAPResponse response) 755 throws LDAPException 756 { 757 try 758 { 759 responseQueue.put(response); 760 } 761 catch (final Exception e) 762 { 763 Debug.debugException(e); 764 765 if (e instanceof InterruptedException) 766 { 767 Thread.currentThread().interrupt(); 768 } 769 770 throw new LDAPException(ResultCode.LOCAL_ERROR, 771 ERR_EXCEPTION_HANDLING_RESPONSE.get( 772 StaticUtils.getExceptionMessage(e)), 773 e); 774 } 775 } 776 777 778 779 /** 780 * {@inheritDoc} 781 */ 782 @Override() 783 public int getLastMessageID() 784 { 785 return messageID; 786 } 787 788 789 790 /** 791 * {@inheritDoc} 792 */ 793 @Override() 794 @NotNull() 795 public OperationType getOperationType() 796 { 797 return OperationType.DELETE; 798 } 799 800 801 802 /** 803 * {@inheritDoc} 804 */ 805 @Override() 806 @NotNull() 807 public DeleteRequest duplicate() 808 { 809 return duplicate(getControls()); 810 } 811 812 813 814 /** 815 * {@inheritDoc} 816 */ 817 @Override() 818 @NotNull() 819 public DeleteRequest duplicate(@Nullable final Control[] controls) 820 { 821 final DeleteRequest r = new DeleteRequest(dn, controls); 822 823 if (followReferralsInternal() != null) 824 { 825 r.setFollowReferrals(followReferralsInternal()); 826 } 827 828 if (getReferralConnectorInternal() != null) 829 { 830 r.setReferralConnector(getReferralConnectorInternal()); 831 } 832 833 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 834 835 return r; 836 } 837 838 839 840 /** 841 * {@inheritDoc} 842 */ 843 @Override() 844 @NotNull() 845 public LDIFDeleteChangeRecord toLDIFChangeRecord() 846 { 847 return new LDIFDeleteChangeRecord(this); 848 } 849 850 851 852 /** 853 * {@inheritDoc} 854 */ 855 @Override() 856 @NotNull() 857 public String[] toLDIF() 858 { 859 return toLDIFChangeRecord().toLDIF(); 860 } 861 862 863 864 /** 865 * {@inheritDoc} 866 */ 867 @Override() 868 @NotNull() 869 public String toLDIFString() 870 { 871 return toLDIFChangeRecord().toLDIFString(); 872 } 873 874 875 876 /** 877 * {@inheritDoc} 878 */ 879 @Override() 880 public void toString(@NotNull final StringBuilder buffer) 881 { 882 buffer.append("DeleteRequest(dn='"); 883 buffer.append(dn); 884 buffer.append('\''); 885 886 final Control[] controls = getControls(); 887 if (controls.length > 0) 888 { 889 buffer.append(", controls={"); 890 for (int i=0; i < controls.length; i++) 891 { 892 if (i > 0) 893 { 894 buffer.append(", "); 895 } 896 897 buffer.append(controls[i]); 898 } 899 buffer.append('}'); 900 } 901 902 buffer.append(')'); 903 } 904 905 906 907 /** 908 * {@inheritDoc} 909 */ 910 @Override() 911 public void toCode(@NotNull final List<String> lineList, 912 @NotNull final String requestID, 913 final int indentSpaces, final boolean includeProcessing) 914 { 915 // Create the request variable. 916 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "DeleteRequest", 917 requestID + "Request", "new DeleteRequest", 918 ToCodeArgHelper.createString(dn, "Entry DN")); 919 920 // If there are any controls, then add them to the request. 921 for (final Control c : getControls()) 922 { 923 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 924 requestID + "Request.addControl", 925 ToCodeArgHelper.createControl(c, null)); 926 } 927 928 929 // Add lines for processing the request and obtaining the result. 930 if (includeProcessing) 931 { 932 // Generate a string with the appropriate indent. 933 final StringBuilder buffer = new StringBuilder(); 934 for (int i=0; i < indentSpaces; i++) 935 { 936 buffer.append(' '); 937 } 938 final String indent = buffer.toString(); 939 940 lineList.add(""); 941 lineList.add(indent + "try"); 942 lineList.add(indent + '{'); 943 lineList.add(indent + " LDAPResult " + requestID + 944 "Result = connection.delete(" + requestID + "Request);"); 945 lineList.add(indent + " // The delete was processed successfully."); 946 lineList.add(indent + '}'); 947 lineList.add(indent + "catch (LDAPException e)"); 948 lineList.add(indent + '{'); 949 lineList.add(indent + " // The delete failed. Maybe the following " + 950 "will help explain why."); 951 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 952 lineList.add(indent + " String message = e.getMessage();"); 953 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 954 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 955 lineList.add(indent + " Control[] responseControls = " + 956 "e.getResponseControls();"); 957 lineList.add(indent + '}'); 958 } 959 } 960}