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 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 }