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 com.unboundid.ldap.sdk.ChangeType;
026    import com.unboundid.ldap.sdk.DN;
027    import com.unboundid.ldap.sdk.Entry;
028    import com.unboundid.ldap.sdk.LDAPException;
029    import com.unboundid.ldap.sdk.LDAPInterface;
030    import com.unboundid.ldap.sdk.LDAPResult;
031    import com.unboundid.util.ByteStringBuffer;
032    import com.unboundid.util.NotExtensible;
033    import com.unboundid.util.ThreadSafety;
034    import com.unboundid.util.ThreadSafetyLevel;
035    
036    import static com.unboundid.util.Validator.*;
037    
038    
039    
040    /**
041     * This class provides a base class for LDIF change records, which can be used
042     * to represent add, delete, modify, and modify DN operations in LDIF form.
043     * <BR><BR>
044     * <H2>Example</H2>
045     * The following example iterates through all of the change records contained in
046     * an LDIF file and attempts to apply those changes to a directory server:
047     * <PRE>
048     *   LDIFReader ldifReader = new LDIFReader(pathToLDIFFile);
049     *
050     *   while (true)
051     *   {
052     *     LDIFChangeRecord changeRecord;
053     *     try
054     *     {
055     *       changeRecord = ldifReader.readChangeRecord();
056     *       if (changeRecord == null)
057     *       {
058     *         System.err.println("All changes have been processed.");
059     *         break;
060     *       }
061     *     }
062     *     catch (LDIFException le)
063     *     {
064     *       if (le.mayContinueReading())
065     *       {
066     *         System.err.println("A recoverable occurred while attempting to " +
067     *              "read a change record at or near line number " +
068     *              le.getLineNumber() + ":  " + le.getMessage());
069     *         System.err.println("The change record will be skipped.");
070     *         continue;
071     *       }
072     *       else
073     *       {
074     *         System.err.println("An unrecoverable occurred while attempting to " +
075     *              "read a change record at or near line number " +
076     *              le.getLineNumber() + ":  " + le.getMessage());
077     *         System.err.println("LDIF processing will be aborted.");
078     *         break;
079     *       }
080     *     }
081     *     catch (IOException ioe)
082     *     {
083     *       System.err.println("An I/O error occurred while attempting to read " +
084     *            "from the LDIF file:  " + ioe.getMessage());
085     *       System.err.println("LDIF processing will be aborted.");
086     *       break;
087     *     }
088     *
089     *     try
090     *     {
091     *       LDAPResult result = changeRecord.processChange(connection);
092     *       System.out.println(changeRecord.getChangeType().getName() +
093     *            " successful for entry " + changeRecord.getDN());
094     *     }
095     *     catch (LDAPException le)
096     *     {
097     *       System.err.println(changeRecord.getChangeType().getName() +
098     *            " failed for entry " + changeRecord.getDN() + " -- " +
099     *            le.getMessage());
100     *     }
101     *   }
102     *
103     *   ldifReader.close();
104     * </PRE>
105     */
106    @NotExtensible()
107    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
108    public abstract class LDIFChangeRecord
109           implements LDIFRecord
110    {
111      /**
112       * The serial version UID for this serializable class.
113       */
114      private static final long serialVersionUID = 2394617613961232499L;
115    
116    
117    
118      // The parsed DN for this LDIF change record.
119      private volatile DN parsedDN;
120    
121      // The DN for this LDIF change record.
122      private final String dn;
123    
124    
125    
126      /**
127       * Creates a new LDIF change record with the provided DN.
128       *
129       * @param  dn  The DN of the LDIF change record to create.  It must not be
130       *             {@code null}.
131       */
132      protected LDIFChangeRecord(final String dn)
133      {
134        ensureNotNull(dn);
135    
136        this.dn = dn;
137      }
138    
139    
140    
141      /**
142       * Retrieves the DN for this LDIF change record.
143       *
144       * @return  The DN for this LDIF change record.
145       */
146      public final String getDN()
147      {
148        return dn;
149      }
150    
151    
152    
153      /**
154       * Retrieves the parsed DN for this LDIF change record.
155       *
156       * @return  The DN for this LDIF change record.
157       *
158       * @throws  LDAPException  If a problem occurs while trying to parse the DN.
159       */
160      public final DN getParsedDN()
161             throws LDAPException
162      {
163        if (parsedDN == null)
164        {
165          parsedDN = new DN(dn);
166        }
167    
168        return parsedDN;
169      }
170    
171    
172    
173      /**
174       * Retrieves the type of operation represented by this LDIF change record.
175       *
176       * @return  The type of operation represented by this LDIF change record.
177       */
178      public abstract ChangeType getChangeType();
179    
180    
181    
182      /**
183       * Apply the change represented by this LDIF change record to a directory
184       * server using the provided connection.
185       *
186       * @param  connection  The connection to use to apply the change.
187       *
188       * @return  An object providing information about the result of the operation.
189       *
190       * @throws  LDAPException  If an error occurs while processing this change
191       *                         in the associated directory server.
192       */
193      public abstract LDAPResult processChange(final LDAPInterface connection)
194             throws LDAPException;
195    
196    
197    
198      /**
199       * Retrieves an {@code Entry} representation of this change record.  This is
200       * intended only for internal use by the LDIF reader when operating
201       * asynchronously in the case that it is not possible to know ahead of time
202       * whether a user will attempt to read an LDIF record by {@code readEntry} or
203       * {@code readChangeRecord}.  In the event that the LDIF file has an entry
204       * whose first attribute is "changetype" and the client wants to read it as
205       * an entry rather than a change record, then this may be used to generate an
206       * entry representing the change record.
207       *
208       * @return  The entry representation of this change record.
209       *
210       * @throws  LDIFException  If this change record cannot be represented as a
211       *                         valid entry.
212       */
213      final Entry toEntry()
214            throws LDIFException
215      {
216        return new Entry(toLDIF());
217      }
218    
219    
220    
221      /**
222       * Retrieves a string array whose lines contain an LDIF representation of this
223       * change record.
224       *
225       * @return  A string array whose lines contain an LDIF representation of this
226       *          change record.
227       */
228      public final String[] toLDIF()
229      {
230        return toLDIF(0);
231      }
232    
233    
234    
235      /**
236       * Retrieves a string array whose lines contain an LDIF representation of this
237       * change record.
238       *
239       * @param  wrapColumn  The column at which to wrap long lines.  A value that
240       *                     is less than or equal to two indicates that no
241       *                     wrapping should be performed.
242       *
243       * @return  A string array whose lines contain an LDIF representation of this
244       *          change record.
245       */
246      public abstract String[] toLDIF(final int wrapColumn);
247    
248    
249    
250      /**
251       * Appends an LDIF string representation of this change record to the provided
252       * buffer.
253       *
254       * @param  buffer  The buffer to which to append an LDIF representation of
255       *                 this change record.
256       */
257      public final void toLDIF(final ByteStringBuffer buffer)
258      {
259        toLDIF(buffer, 0);
260      }
261    
262    
263    
264      /**
265       * Appends an LDIF string representation of this change record to the provided
266       * buffer.
267       *
268       * @param  buffer      The buffer to which to append an LDIF representation of
269       *                     this change record.
270       * @param  wrapColumn  The column at which to wrap long lines.  A value that
271       *                     is less than or equal to two indicates that no
272       *                     wrapping should be performed.
273       */
274      public abstract void toLDIF(final ByteStringBuffer buffer,
275                                  final int wrapColumn);
276    
277    
278    
279      /**
280       * Retrieves an LDIF string representation of this change record.
281       *
282       * @return  An LDIF string representation of this change record.
283       */
284      public final String toLDIFString()
285      {
286        final StringBuilder buffer = new StringBuilder();
287        toLDIFString(buffer, 0);
288        return buffer.toString();
289      }
290    
291    
292    
293      /**
294       * Retrieves an LDIF string representation of this change record.
295       *
296       * @param  wrapColumn  The column at which to wrap long lines.  A value that
297       *                     is less than or equal to two indicates that no
298       *                     wrapping should be performed.
299       *
300       * @return  An LDIF string representation of this change record.
301       */
302      public final String toLDIFString(final int wrapColumn)
303      {
304        final StringBuilder buffer = new StringBuilder();
305        toLDIFString(buffer, wrapColumn);
306        return buffer.toString();
307      }
308    
309    
310    
311      /**
312       * Appends an LDIF string representation of this change record to the provided
313       * buffer.
314       *
315       * @param  buffer  The buffer to which to append an LDIF representation of
316       *                 this change record.
317       */
318      public final void toLDIFString(final StringBuilder buffer)
319      {
320        toLDIFString(buffer, 0);
321      }
322    
323    
324    
325      /**
326       * Appends an LDIF string representation of this change record to the provided
327       * buffer.
328       *
329       * @param  buffer      The buffer to which to append an LDIF representation of
330       *                     this change record.
331       * @param  wrapColumn  The column at which to wrap long lines.  A value that
332       *                     is less than or equal to two indicates that no
333       *                     wrapping should be performed.
334       */
335      public abstract void toLDIFString(final StringBuilder buffer,
336                                        final int wrapColumn);
337    
338    
339    
340      /**
341       * Retrieves a hash code for this change record.
342       *
343       * @return  A hash code for this change record.
344       */
345      @Override()
346      public abstract int hashCode();
347    
348    
349    
350      /**
351       * Indicates whether the provided object is equal to this LDIF change record.
352       *
353       * @param  o  The object for which to make the determination.
354       *
355       * @return  {@code true} if the provided object is equal to this LDIF change
356       *          record, or {@code false} if not.
357       */
358      @Override()
359      public abstract boolean equals(final Object o);
360    
361    
362    
363      /**
364       * Retrieves a single-line string representation of this change record.
365       *
366       * @return  A single-line string representation of this change record.
367       */
368      @Override()
369      public final String toString()
370      {
371        final StringBuilder buffer = new StringBuilder();
372        toString(buffer);
373        return buffer.toString();
374      }
375    
376    
377    
378      /**
379       * Appends a single-line string representation of this change record to the
380       * provided buffer.
381       *
382       * @param  buffer  The buffer to which the information should be written.
383       */
384      public abstract void toString(final StringBuilder buffer);
385    }