001/* 002 * Copyright 2007-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldif; 022 023 024 025import java.util.ArrayList; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.List; 029 030import com.unboundid.asn1.ASN1OctetString; 031import com.unboundid.ldap.sdk.ChangeType; 032import com.unboundid.ldap.sdk.Control; 033import com.unboundid.ldap.sdk.DN; 034import com.unboundid.ldap.sdk.LDAPException; 035import com.unboundid.ldap.sdk.LDAPInterface; 036import com.unboundid.ldap.sdk.LDAPResult; 037import com.unboundid.ldap.sdk.ModifyDNRequest; 038import com.unboundid.ldap.sdk.RDN; 039import com.unboundid.util.ByteStringBuffer; 040import com.unboundid.util.NotMutable; 041import com.unboundid.util.ThreadSafety; 042import com.unboundid.util.ThreadSafetyLevel; 043 044import static com.unboundid.util.Debug.*; 045import static com.unboundid.util.StaticUtils.*; 046import static com.unboundid.util.Validator.*; 047 048 049 050/** 051 * This class defines an LDIF modify DN change record, which can be used to 052 * represent an LDAP modify DN request. See the documentation for the 053 * {@link LDIFChangeRecord} class for an example demonstrating the process for 054 * interacting with LDIF change records. 055 */ 056@NotMutable() 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public final class LDIFModifyDNChangeRecord 059 extends LDIFChangeRecord 060{ 061 /** 062 * The serial version UID for this serializable class. 063 */ 064 private static final long serialVersionUID = 5804442145450388071L; 065 066 067 068 // Indicates whether to delete the current RDN value. 069 private final boolean deleteOldRDN; 070 071 // The parsed new superior DN for the entry. 072 private volatile DN parsedNewSuperiorDN; 073 074 // The parsed new RDN for the entry. 075 private volatile RDN parsedNewRDN; 076 077 // The new RDN value for the entry. 078 private final String newRDN; 079 080 // The new superior DN for the entry, if available. 081 private final String newSuperiorDN; 082 083 084 085 /** 086 * Creates a new LDIF modify DN change record with the provided information. 087 * 088 * @param dn The current DN for the entry. It must not be 089 * {@code null}. 090 * @param newRDN The new RDN value for the entry. It must not be 091 * {@code null}. 092 * @param deleteOldRDN Indicates whether to delete the currentRDN value 093 * from the entry. 094 * @param newSuperiorDN The new superior DN for this LDIF modify DN change 095 * record. It may be {@code null} if the entry is not 096 * to be moved below a new parent. 097 */ 098 public LDIFModifyDNChangeRecord(final String dn, final String newRDN, 099 final boolean deleteOldRDN, 100 final String newSuperiorDN) 101 { 102 this(dn, newRDN, deleteOldRDN, newSuperiorDN, null); 103 } 104 105 106 107 /** 108 * Creates a new LDIF modify DN change record with the provided information. 109 * 110 * @param dn The current DN for the entry. It must not be 111 * {@code null}. 112 * @param newRDN The new RDN value for the entry. It must not be 113 * {@code null}. 114 * @param deleteOldRDN Indicates whether to delete the currentRDN value 115 * from the entry. 116 * @param newSuperiorDN The new superior DN for this LDIF modify DN change 117 * record. It may be {@code null} if the entry is not 118 * to be moved below a new parent. 119 * @param controls The set of controls for this LDIF modify DN change 120 * record. It may be {@code null} or empty if there 121 * are no controls. 122 */ 123 public LDIFModifyDNChangeRecord(final String dn, final String newRDN, 124 final boolean deleteOldRDN, 125 final String newSuperiorDN, 126 final List<Control> controls) 127 { 128 super(dn, controls); 129 130 ensureNotNull(newRDN); 131 132 this.newRDN = newRDN; 133 this.deleteOldRDN = deleteOldRDN; 134 this.newSuperiorDN = newSuperiorDN; 135 136 parsedNewRDN = null; 137 parsedNewSuperiorDN = null; 138 } 139 140 141 142 /** 143 * Creates a new LDIF modify DN change record from the provided modify DN 144 * request. 145 * 146 * @param modifyDNRequest The modify DN request to use to create this LDIF 147 * modify DN change record. It must not be 148 * {@code null}. 149 */ 150 public LDIFModifyDNChangeRecord(final ModifyDNRequest modifyDNRequest) 151 { 152 super(modifyDNRequest.getDN(), modifyDNRequest.getControlList()); 153 154 newRDN = modifyDNRequest.getNewRDN(); 155 deleteOldRDN = modifyDNRequest.deleteOldRDN(); 156 newSuperiorDN = modifyDNRequest.getNewSuperiorDN(); 157 158 parsedNewRDN = null; 159 parsedNewSuperiorDN = null; 160 } 161 162 163 164 /** 165 * Retrieves the new RDN value for the entry. 166 * 167 * @return The new RDN value for the entry. 168 */ 169 public String getNewRDN() 170 { 171 return newRDN; 172 } 173 174 175 176 /** 177 * Retrieves the parsed new RDN value for the entry. 178 * 179 * @return The parsed new RDN value for the entry. 180 * 181 * @throws LDAPException If a problem occurs while trying to parse the new 182 * RDN. 183 */ 184 public RDN getParsedNewRDN() 185 throws LDAPException 186 { 187 if (parsedNewRDN == null) 188 { 189 parsedNewRDN = new RDN(newRDN); 190 } 191 192 return parsedNewRDN; 193 } 194 195 196 197 /** 198 * Indicates whether to delete the current RDN value from the entry. 199 * 200 * @return {@code true} if the current RDN value should be removed from the 201 * entry, or {@code false} if not. 202 */ 203 public boolean deleteOldRDN() 204 { 205 return deleteOldRDN; 206 } 207 208 209 210 /** 211 * Retrieves the new superior DN for the entry, if applicable. 212 * 213 * @return The new superior DN for the entry, or {@code null} if the entry is 214 * not to be moved below a new parent. 215 */ 216 public String getNewSuperiorDN() 217 { 218 return newSuperiorDN; 219 } 220 221 222 223 /** 224 * Retrieves the parsed new superior DN for the entry, if applicable. 225 * 226 * @return The parsed new superior DN for the entry, or {@code null} if the 227 * entry is not to be moved below a new parent. 228 * 229 * @throws LDAPException If a problem occurs while trying to parse the new 230 * superior DN. 231 */ 232 public DN getParsedNewSuperiorDN() 233 throws LDAPException 234 { 235 if ((parsedNewSuperiorDN == null) && (newSuperiorDN != null)) 236 { 237 parsedNewSuperiorDN = new DN(newSuperiorDN); 238 } 239 240 return parsedNewSuperiorDN; 241 } 242 243 244 245 /** 246 * Retrieves the DN that the entry should have after the successful completion 247 * of the operation. 248 * 249 * @return The DN that the entry should have after the successful completion 250 * of the operation. 251 * 252 * @throws LDAPException If a problem occurs while trying to parse the 253 * target DN, new RDN, or new superior DN. 254 */ 255 public DN getNewDN() 256 throws LDAPException 257 { 258 if (newSuperiorDN == null) 259 { 260 final DN parentDN = getParsedDN().getParent(); 261 if (parentDN == null) 262 { 263 return new DN(getParsedNewRDN()); 264 } 265 else 266 { 267 return new DN(getParsedNewRDN(), parentDN); 268 } 269 } 270 else 271 { 272 return new DN(getParsedNewRDN(), getParsedNewSuperiorDN()); 273 } 274 } 275 276 277 278 /** 279 * Creates a modify DN request from this LDIF modify DN change record. Any 280 * change record controls will be included in the request 281 * 282 * @return The modify DN request created from this LDIF modify DN change 283 * record. 284 */ 285 public ModifyDNRequest toModifyDNRequest() 286 { 287 return toModifyDNRequest(true); 288 } 289 290 291 292 /** 293 * Creates a modify DN request from this LDIF modify DN change record, 294 * optionally including any change record controls in the request. 295 * 296 * @param includeControls Indicates whether to include any controls in the 297 * request. 298 * 299 * @return The modify DN request created from this LDIF modify DN change 300 * record. 301 */ 302 public ModifyDNRequest toModifyDNRequest(final boolean includeControls) 303 { 304 final ModifyDNRequest modifyDNRequest = 305 new ModifyDNRequest(getDN(), newRDN, deleteOldRDN, newSuperiorDN); 306 if (includeControls) 307 { 308 modifyDNRequest.setControls(getControls()); 309 } 310 311 return modifyDNRequest; 312 } 313 314 315 316 /** 317 * {@inheritDoc} 318 */ 319 @Override() 320 public ChangeType getChangeType() 321 { 322 return ChangeType.MODIFY_DN; 323 } 324 325 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override() 331 public LDAPResult processChange(final LDAPInterface connection, 332 final boolean includeControls) 333 throws LDAPException 334 { 335 return connection.modifyDN(toModifyDNRequest(includeControls)); 336 } 337 338 339 340 /** 341 * {@inheritDoc} 342 */ 343 @Override() 344 public String[] toLDIF(final int wrapColumn) 345 { 346 List<String> ldifLines = new ArrayList<String>(10); 347 encodeNameAndValue("dn", new ASN1OctetString(getDN()), ldifLines); 348 349 for (final Control c : getControls()) 350 { 351 encodeNameAndValue("control", encodeControlString(c), ldifLines); 352 } 353 354 ldifLines.add("changetype: moddn"); 355 encodeNameAndValue("newrdn", new ASN1OctetString(newRDN), ldifLines); 356 ldifLines.add("deleteoldrdn: " + (deleteOldRDN ? "1" : "0")); 357 358 if (newSuperiorDN != null) 359 { 360 encodeNameAndValue("newsuperior", new ASN1OctetString(newSuperiorDN), 361 ldifLines); 362 } 363 364 if (wrapColumn > 2) 365 { 366 ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines); 367 } 368 369 final String[] ldifArray = new String[ldifLines.size()]; 370 ldifLines.toArray(ldifArray); 371 return ldifArray; 372 } 373 374 375 376 /** 377 * {@inheritDoc} 378 */ 379 @Override() 380 public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn) 381 { 382 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 383 wrapColumn); 384 buffer.append(EOL_BYTES); 385 386 for (final Control c : getControls()) 387 { 388 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 389 wrapColumn); 390 buffer.append(EOL_BYTES); 391 } 392 393 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("moddn"), 394 buffer, wrapColumn); 395 buffer.append(EOL_BYTES); 396 397 LDIFWriter.encodeNameAndValue("newrdn", new ASN1OctetString(newRDN), buffer, 398 wrapColumn); 399 buffer.append(EOL_BYTES); 400 401 if (deleteOldRDN) 402 { 403 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("1"), 404 buffer, wrapColumn); 405 } 406 else 407 { 408 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("0"), 409 buffer, wrapColumn); 410 } 411 buffer.append(EOL_BYTES); 412 413 if (newSuperiorDN != null) 414 { 415 LDIFWriter.encodeNameAndValue("newsuperior", 416 new ASN1OctetString(newSuperiorDN), buffer, 417 wrapColumn); 418 buffer.append(EOL_BYTES); 419 } 420 } 421 422 423 424 /** 425 * {@inheritDoc} 426 */ 427 @Override() 428 public void toLDIFString(final StringBuilder buffer, final int wrapColumn) 429 { 430 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 431 wrapColumn); 432 buffer.append(EOL); 433 434 for (final Control c : getControls()) 435 { 436 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 437 wrapColumn); 438 buffer.append(EOL); 439 } 440 441 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("moddn"), 442 buffer, wrapColumn); 443 buffer.append(EOL); 444 445 LDIFWriter.encodeNameAndValue("newrdn", new ASN1OctetString(newRDN), buffer, 446 wrapColumn); 447 buffer.append(EOL); 448 449 if (deleteOldRDN) 450 { 451 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("1"), 452 buffer, wrapColumn); 453 } 454 else 455 { 456 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("0"), 457 buffer, wrapColumn); 458 } 459 buffer.append(EOL); 460 461 if (newSuperiorDN != null) 462 { 463 LDIFWriter.encodeNameAndValue("newsuperior", 464 new ASN1OctetString(newSuperiorDN), buffer, 465 wrapColumn); 466 buffer.append(EOL); 467 } 468 } 469 470 471 472 /** 473 * {@inheritDoc} 474 */ 475 @Override() 476 public int hashCode() 477 { 478 int hashCode; 479 try 480 { 481 hashCode = getParsedDN().hashCode() + getParsedNewRDN().hashCode(); 482 if (newSuperiorDN != null) 483 { 484 hashCode += getParsedNewSuperiorDN().hashCode(); 485 } 486 } 487 catch (final Exception e) 488 { 489 debugException(e); 490 hashCode = toLowerCase(getDN()).hashCode() + 491 toLowerCase(newRDN).hashCode(); 492 if (newSuperiorDN != null) 493 { 494 hashCode += toLowerCase(newSuperiorDN).hashCode(); 495 } 496 } 497 498 if (deleteOldRDN) 499 { 500 hashCode++; 501 } 502 503 return hashCode; 504 } 505 506 507 508 /** 509 * {@inheritDoc} 510 */ 511 @Override() 512 public boolean equals(final Object o) 513 { 514 if (o == null) 515 { 516 return false; 517 } 518 519 if (o == this) 520 { 521 return true; 522 } 523 524 if (! (o instanceof LDIFModifyDNChangeRecord)) 525 { 526 return false; 527 } 528 529 final LDIFModifyDNChangeRecord r = (LDIFModifyDNChangeRecord) o; 530 531 final HashSet<Control> c1 = new HashSet<Control>(getControls()); 532 final HashSet<Control> c2 = new HashSet<Control>(r.getControls()); 533 if (! c1.equals(c2)) 534 { 535 return false; 536 } 537 538 try 539 { 540 if (! getParsedDN().equals(r.getParsedDN())) 541 { 542 return false; 543 } 544 } 545 catch (final Exception e) 546 { 547 debugException(e); 548 if (! toLowerCase(getDN()).equals(toLowerCase(r.getDN()))) 549 { 550 return false; 551 } 552 } 553 554 try 555 { 556 if (! getParsedNewRDN().equals(r.getParsedNewRDN())) 557 { 558 return false; 559 } 560 } 561 catch (final Exception e) 562 { 563 debugException(e); 564 if (! toLowerCase(newRDN).equals(toLowerCase(r.newRDN))) 565 { 566 return false; 567 } 568 } 569 570 if (newSuperiorDN == null) 571 { 572 if (r.newSuperiorDN != null) 573 { 574 return false; 575 } 576 } 577 else 578 { 579 if (r.newSuperiorDN == null) 580 { 581 return false; 582 } 583 584 try 585 { 586 if (! getParsedNewSuperiorDN().equals(r.getParsedNewSuperiorDN())) 587 { 588 return false; 589 } 590 } 591 catch (final Exception e) 592 { 593 debugException(e); 594 if (! toLowerCase(newSuperiorDN).equals(toLowerCase(r.newSuperiorDN))) 595 { 596 return false; 597 } 598 } 599 } 600 601 return (deleteOldRDN == r.deleteOldRDN); 602 } 603 604 605 606 /** 607 * {@inheritDoc} 608 */ 609 @Override() 610 public void toString(final StringBuilder buffer) 611 { 612 buffer.append("LDIFModifyDNChangeRecord(dn='"); 613 buffer.append(getDN()); 614 buffer.append("', newRDN='"); 615 buffer.append(newRDN); 616 buffer.append("', deleteOldRDN="); 617 buffer.append(deleteOldRDN); 618 619 if (newSuperiorDN != null) 620 { 621 buffer.append(", newSuperiorDN='"); 622 buffer.append(newSuperiorDN); 623 buffer.append('\''); 624 } 625 626 final List<Control> controls = getControls(); 627 if (! controls.isEmpty()) 628 { 629 buffer.append(", controls={"); 630 631 final Iterator<Control> iterator = controls.iterator(); 632 while (iterator.hasNext()) 633 { 634 iterator.next().toString(buffer); 635 if (iterator.hasNext()) 636 { 637 buffer.append(','); 638 } 639 } 640 641 buffer.append('}'); 642 } 643 644 buffer.append(')'); 645 } 646}