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