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