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 import com.unboundid.util.NotMutable;
041 import com.unboundid.util.ThreadSafety;
042 import com.unboundid.util.ThreadSafetyLevel;
043
044 import static com.unboundid.util.Debug.*;
045 import static com.unboundid.util.StaticUtils.*;
046 import 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)
058 public 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 }