001 /* 002 * Copyright 2007-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2008-2014 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 ldifLines.add(LDIFWriter.encodeNameAndValue("dn", 343 new ASN1OctetString(getDN()))); 344 345 for (final Control c : getControls()) 346 { 347 ldifLines.add(LDIFWriter.encodeNameAndValue("control", 348 encodeControlString(c))); 349 } 350 351 ldifLines.add("changetype: moddn"); 352 ldifLines.add(LDIFWriter.encodeNameAndValue("newrdn", 353 new ASN1OctetString(newRDN))); 354 ldifLines.add("deleteoldrdn: " + (deleteOldRDN ? "1" : "0")); 355 356 if (newSuperiorDN != null) 357 { 358 ldifLines.add(LDIFWriter.encodeNameAndValue("newsuperior", 359 new ASN1OctetString(newSuperiorDN))); 360 } 361 362 if (wrapColumn > 2) 363 { 364 ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines); 365 } 366 367 final String[] ldifArray = new String[ldifLines.size()]; 368 ldifLines.toArray(ldifArray); 369 return ldifArray; 370 } 371 372 373 374 /** 375 * {@inheritDoc} 376 */ 377 @Override() 378 public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn) 379 { 380 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 381 wrapColumn); 382 buffer.append(EOL_BYTES); 383 384 for (final Control c : getControls()) 385 { 386 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 387 wrapColumn); 388 buffer.append(EOL_BYTES); 389 } 390 391 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("moddn"), 392 buffer, wrapColumn); 393 buffer.append(EOL_BYTES); 394 395 LDIFWriter.encodeNameAndValue("newrdn", new ASN1OctetString(newRDN), buffer, 396 wrapColumn); 397 buffer.append(EOL_BYTES); 398 399 if (deleteOldRDN) 400 { 401 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("1"), 402 buffer, wrapColumn); 403 } 404 else 405 { 406 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("0"), 407 buffer, wrapColumn); 408 } 409 buffer.append(EOL_BYTES); 410 411 if (newSuperiorDN != null) 412 { 413 LDIFWriter.encodeNameAndValue("newsuperior", 414 new ASN1OctetString(newSuperiorDN), buffer, 415 wrapColumn); 416 buffer.append(EOL_BYTES); 417 } 418 } 419 420 421 422 /** 423 * {@inheritDoc} 424 */ 425 @Override() 426 public void toLDIFString(final StringBuilder buffer, final int wrapColumn) 427 { 428 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 429 wrapColumn); 430 buffer.append(EOL); 431 432 for (final Control c : getControls()) 433 { 434 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 435 wrapColumn); 436 buffer.append(EOL); 437 } 438 439 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("moddn"), 440 buffer, wrapColumn); 441 buffer.append(EOL); 442 443 LDIFWriter.encodeNameAndValue("newrdn", new ASN1OctetString(newRDN), buffer, 444 wrapColumn); 445 buffer.append(EOL); 446 447 if (deleteOldRDN) 448 { 449 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("1"), 450 buffer, wrapColumn); 451 } 452 else 453 { 454 LDIFWriter.encodeNameAndValue("deleteoldrdn", new ASN1OctetString("0"), 455 buffer, wrapColumn); 456 } 457 buffer.append(EOL); 458 459 if (newSuperiorDN != null) 460 { 461 LDIFWriter.encodeNameAndValue("newsuperior", 462 new ASN1OctetString(newSuperiorDN), buffer, 463 wrapColumn); 464 buffer.append(EOL); 465 } 466 } 467 468 469 470 /** 471 * {@inheritDoc} 472 */ 473 @Override() 474 public int hashCode() 475 { 476 int hashCode; 477 try 478 { 479 hashCode = getParsedDN().hashCode() + getParsedNewRDN().hashCode(); 480 if (newSuperiorDN != null) 481 { 482 hashCode += getParsedNewSuperiorDN().hashCode(); 483 } 484 } 485 catch (final Exception e) 486 { 487 debugException(e); 488 hashCode = toLowerCase(getDN()).hashCode() + 489 toLowerCase(newRDN).hashCode(); 490 if (newSuperiorDN != null) 491 { 492 hashCode += toLowerCase(newSuperiorDN).hashCode(); 493 } 494 } 495 496 if (deleteOldRDN) 497 { 498 hashCode++; 499 } 500 501 return hashCode; 502 } 503 504 505 506 /** 507 * {@inheritDoc} 508 */ 509 @Override() 510 public boolean equals(final Object o) 511 { 512 if (o == null) 513 { 514 return false; 515 } 516 517 if (o == this) 518 { 519 return true; 520 } 521 522 if (! (o instanceof LDIFModifyDNChangeRecord)) 523 { 524 return false; 525 } 526 527 final LDIFModifyDNChangeRecord r = (LDIFModifyDNChangeRecord) o; 528 529 final HashSet<Control> c1 = new HashSet<Control>(getControls()); 530 final HashSet<Control> c2 = new HashSet<Control>(r.getControls()); 531 if (! c1.equals(c2)) 532 { 533 return false; 534 } 535 536 try 537 { 538 if (! getParsedDN().equals(r.getParsedDN())) 539 { 540 return false; 541 } 542 } 543 catch (final Exception e) 544 { 545 debugException(e); 546 if (! toLowerCase(getDN()).equals(toLowerCase(r.getDN()))) 547 { 548 return false; 549 } 550 } 551 552 try 553 { 554 if (! getParsedNewRDN().equals(r.getParsedNewRDN())) 555 { 556 return false; 557 } 558 } 559 catch (final Exception e) 560 { 561 debugException(e); 562 if (! toLowerCase(newRDN).equals(toLowerCase(r.newRDN))) 563 { 564 return false; 565 } 566 } 567 568 if (newSuperiorDN == null) 569 { 570 if (r.newSuperiorDN != null) 571 { 572 return false; 573 } 574 } 575 else 576 { 577 if (r.newSuperiorDN == null) 578 { 579 return false; 580 } 581 582 try 583 { 584 if (! getParsedNewSuperiorDN().equals(r.getParsedNewSuperiorDN())) 585 { 586 return false; 587 } 588 } 589 catch (final Exception e) 590 { 591 debugException(e); 592 if (! toLowerCase(newSuperiorDN).equals(toLowerCase(r.newSuperiorDN))) 593 { 594 return false; 595 } 596 } 597 } 598 599 return (deleteOldRDN == r.deleteOldRDN); 600 } 601 602 603 604 /** 605 * {@inheritDoc} 606 */ 607 @Override() 608 public void toString(final StringBuilder buffer) 609 { 610 buffer.append("LDIFModifyDNChangeRecord(dn='"); 611 buffer.append(getDN()); 612 buffer.append("', newRDN='"); 613 buffer.append(newRDN); 614 buffer.append("', deleteOldRDN="); 615 buffer.append(deleteOldRDN); 616 617 if (newSuperiorDN != null) 618 { 619 buffer.append(", newSuperiorDN='"); 620 buffer.append(newSuperiorDN); 621 buffer.append('\''); 622 } 623 624 final List<Control> controls = getControls(); 625 if (! controls.isEmpty()) 626 { 627 buffer.append(", controls={"); 628 629 final Iterator<Control> iterator = controls.iterator(); 630 while (iterator.hasNext()) 631 { 632 iterator.next().toString(buffer); 633 if (iterator.hasNext()) 634 { 635 buffer.append(','); 636 } 637 } 638 639 buffer.append('}'); 640 } 641 642 buffer.append(')'); 643 } 644 }