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