001    /*
002     * Copyright 2007-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 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.Collection;
027    import java.util.HashSet;
028    import java.util.Iterator;
029    import java.util.List;
030    
031    import com.unboundid.asn1.ASN1OctetString;
032    import com.unboundid.ldap.sdk.AddRequest;
033    import com.unboundid.ldap.sdk.Attribute;
034    import com.unboundid.ldap.sdk.ChangeType;
035    import com.unboundid.ldap.sdk.Control;
036    import com.unboundid.ldap.sdk.Entry;
037    import com.unboundid.ldap.sdk.LDAPException;
038    import com.unboundid.ldap.sdk.LDAPInterface;
039    import com.unboundid.ldap.sdk.LDAPResult;
040    import com.unboundid.util.ByteStringBuffer;
041    
042    import static com.unboundid.util.Debug.*;
043    import static com.unboundid.util.StaticUtils.*;
044    import static com.unboundid.util.Validator.*;
045    
046    
047    
048    /**
049     * This class defines an LDIF add change record, which can be used to represent
050     * an LDAP add request.  See the documentation for the {@code LDIFChangeRecord}
051     * class for an example demonstrating the process for interacting with LDIF
052     * change records.
053     */
054    public final class LDIFAddChangeRecord
055           extends LDIFChangeRecord
056    {
057      /**
058       * The serial version UID for this serializable class.
059       */
060      private static final long serialVersionUID = 4722916031463878423L;
061    
062    
063    
064      // The set of attributes for this add change record.
065      private final Attribute[] attributes;
066    
067    
068    
069      /**
070       * Creates a new LDIF add change record with the provided DN and attributes.
071       *
072       * @param  dn          The DN for this LDIF add change record.  It must not be
073       *                     {@code null}.
074       * @param  attributes  The set of attributes for this LDIF add change record.
075       *                     It must not be {@code null} or empty.
076       */
077      public LDIFAddChangeRecord(final String dn, final Attribute... attributes)
078      {
079        this(dn, attributes, null);
080      }
081    
082    
083    
084      /**
085       * Creates a new LDIF add change record with the provided DN and attributes.
086       *
087       * @param  dn          The DN for this LDIF add change record.  It must not be
088       *                     {@code null}.
089       * @param  attributes  The set of attributes for this LDIF add change record.
090       *                     It must not be {@code null} or empty.
091       * @param  controls    The set of controls for this LDIF add change record.
092       *                     It may be {@code null} or empty if there are no
093       *                     controls.
094       */
095      public LDIFAddChangeRecord(final String dn, final Attribute[] attributes,
096                                 final List<Control> controls)
097      {
098        super(dn, controls);
099    
100        ensureNotNull(attributes);
101        ensureTrue(attributes.length > 0,
102                   "LDIFAddChangeRecord.attributes must not be empty.");
103    
104        this.attributes = attributes;
105      }
106    
107    
108    
109      /**
110       * Creates a new LDIF add change record with the provided DN and attributes.
111       *
112       * @param  dn          The DN for this LDIF add change record.  It must not be
113       *                     {@code null}.
114       * @param  attributes  The set of attributes for this LDIF add change record.
115       *                     It must not be {@code null} or empty.
116       */
117      public LDIFAddChangeRecord(final String dn, final List<Attribute> attributes)
118      {
119        this(dn, attributes, null);
120      }
121    
122    
123    
124      /**
125       * Creates a new LDIF add change record with the provided DN and attributes.
126       *
127       * @param  dn          The DN for this LDIF add change record.  It must not be
128       *                     {@code null}.
129       * @param  attributes  The set of attributes for this LDIF add change record.
130       *                     It must not be {@code null} or empty.
131       * @param  controls    The set of controls for this LDIF add change record.
132       *                     It may be {@code null} or empty if there are no
133       *                     controls.
134       */
135      public LDIFAddChangeRecord(final String dn, final List<Attribute> attributes,
136                                 final List<Control> controls)
137      {
138        super(dn, controls);
139    
140        ensureNotNull(attributes);
141        ensureFalse(attributes.isEmpty(),
142                    "LDIFAddChangeRecord.attributes must not be empty.");
143    
144        this.attributes = new Attribute[attributes.size()];
145        attributes.toArray(this.attributes);
146      }
147    
148    
149    
150      /**
151       * Creates a new LDIF add change record from the provided entry.
152       *
153       * @param  entry  The entry to use to create this LDIF add change record.  It
154       *                must not be {@code null}.
155       */
156      public LDIFAddChangeRecord(final Entry entry)
157      {
158        this(entry, null);
159      }
160    
161    
162    
163      /**
164       * Creates a new LDIF add change record from the provided entry.
165       *
166       * @param  entry     The entry to use to create this LDIF add change record.
167       *                   It must not be {@code null}.
168       * @param  controls  The set of controls for this LDIF add change record.  It
169       *                   may be {@code null} or empty if there are no controls.
170       */
171      public LDIFAddChangeRecord(final Entry entry, final List<Control> controls)
172      {
173        super(entry.getDN(), controls);
174    
175        final Collection<Attribute> attrs = entry.getAttributes();
176        attributes = new Attribute[attrs.size()];
177    
178        final Iterator<Attribute> iterator = attrs.iterator();
179        for (int i=0; i < attributes.length; i++)
180        {
181          attributes[i] = iterator.next();
182        }
183      }
184    
185    
186    
187      /**
188       * Creates a new LDIF add change record from the provided add request.
189       *
190       * @param  addRequest  The add request to use to create this LDIF add change
191       *                     record.  It must not be {@code null}.
192       */
193      public LDIFAddChangeRecord(final AddRequest addRequest)
194      {
195        super(addRequest.getDN(), addRequest.getControlList());
196    
197        final List<Attribute> attrs = addRequest.getAttributes();
198        attributes = new Attribute[attrs.size()];
199    
200        final Iterator<Attribute> iterator = attrs.iterator();
201        for (int i=0; i < attributes.length; i++)
202        {
203          attributes[i] = iterator.next();
204        }
205      }
206    
207    
208    
209      /**
210       * Retrieves the set of attributes for this add change record.
211       *
212       * @return  The set of attributes for this add change record.
213       */
214      public Attribute[] getAttributes()
215      {
216        return attributes;
217      }
218    
219    
220    
221      /**
222       * Retrieves the entry that would be created by this add change record.
223       *
224       * @return  The entry that would be created by this add change record.
225       */
226      public Entry getEntryToAdd()
227      {
228        return new Entry(getDN(), attributes);
229      }
230    
231    
232    
233      /**
234       * Creates an add request from this LDIF add change record.    Any controls
235       * included in this change record will be included in the request.
236       *
237       * @return  The add request created from this LDIF add change record.
238       */
239      public AddRequest toAddRequest()
240      {
241        return toAddRequest(true);
242      }
243    
244    
245    
246      /**
247       * Creates an add request from this LDIF add change record, optionally
248       * including any change record controls in the request.
249       *
250       * @param  includeControls  Indicates whether to include any controls in the
251       *                          request.
252       *
253       * @return  The add request created from this LDIF add change record.
254       */
255      public AddRequest toAddRequest(final boolean includeControls)
256      {
257        final AddRequest addRequest = new AddRequest(getDN(), attributes);
258        if (includeControls)
259        {
260          addRequest.setControls(getControls());
261        }
262    
263        return addRequest;
264      }
265    
266    
267    
268      /**
269       * {@inheritDoc}
270       */
271      @Override()
272      public ChangeType getChangeType()
273      {
274        return ChangeType.ADD;
275      }
276    
277    
278    
279      /**
280       * {@inheritDoc}
281       */
282      @Override()
283      public LDAPResult processChange(final LDAPInterface connection,
284                                      final boolean includeControls)
285             throws LDAPException
286      {
287        return connection.add(toAddRequest(includeControls));
288      }
289    
290    
291    
292      /**
293       * {@inheritDoc}
294       */
295      @Override()
296      public String[] toLDIF(final int wrapColumn)
297      {
298        List<String> ldifLines = new ArrayList<String>(2*attributes.length);
299        ldifLines.add(LDIFWriter.encodeNameAndValue("dn",
300             new ASN1OctetString(getDN())));
301    
302        for (final Control c : getControls())
303        {
304          ldifLines.add(LDIFWriter.encodeNameAndValue("control",
305               encodeControlString(c)));
306        }
307    
308        ldifLines.add("changetype: add");
309    
310        for (final Attribute a : attributes)
311        {
312          final String name = a.getName();
313          for (final ASN1OctetString value : a.getRawValues())
314          {
315            ldifLines.add(LDIFWriter.encodeNameAndValue(name, value));
316          }
317        }
318    
319        if (wrapColumn > 2)
320        {
321          ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines);
322        }
323    
324        final String[] ldifArray = new String[ldifLines.size()];
325        ldifLines.toArray(ldifArray);
326        return ldifArray;
327      }
328    
329    
330    
331      /**
332       * {@inheritDoc}
333       */
334      @Override()
335      public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn)
336      {
337        LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer,
338             wrapColumn);
339        buffer.append(EOL_BYTES);
340    
341        for (final Control c : getControls())
342        {
343          LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer,
344               wrapColumn);
345          buffer.append(EOL_BYTES);
346        }
347    
348        LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"),
349                                      buffer, wrapColumn);
350        buffer.append(EOL_BYTES);
351    
352        for (final Attribute a : attributes)
353        {
354          final String name = a.getName();
355          for (final ASN1OctetString value : a.getRawValues())
356          {
357            LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
358            buffer.append(EOL_BYTES);
359          }
360        }
361      }
362    
363    
364    
365      /**
366       * {@inheritDoc}
367       */
368      @Override()
369      public void toLDIFString(final StringBuilder buffer, final int wrapColumn)
370      {
371        LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer,
372             wrapColumn);
373        buffer.append(EOL);
374    
375        for (final Control c : getControls())
376        {
377          LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer,
378               wrapColumn);
379          buffer.append(EOL);
380        }
381    
382        LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"),
383                                      buffer, wrapColumn);
384        buffer.append(EOL);
385    
386        for (final Attribute a : attributes)
387        {
388          final String name = a.getName();
389          for (final ASN1OctetString value : a.getRawValues())
390          {
391            LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
392            buffer.append(EOL);
393          }
394        }
395      }
396    
397    
398    
399      /**
400       * {@inheritDoc}
401       */
402      @Override()
403      public int hashCode()
404      {
405        try
406        {
407          int hashCode = getParsedDN().hashCode();
408          for (final Attribute a : attributes)
409          {
410            hashCode += a.hashCode();
411          }
412    
413          return hashCode;
414        }
415        catch (final Exception e)
416        {
417          debugException(e);
418          return new Entry(getDN(), attributes).hashCode();
419        }
420      }
421    
422    
423    
424      /**
425       * {@inheritDoc}
426       */
427      @Override()
428      public boolean equals(final Object o)
429      {
430        if (o == null)
431        {
432          return false;
433        }
434    
435        if (o == this)
436        {
437          return true;
438        }
439    
440        if (! (o instanceof LDIFAddChangeRecord))
441        {
442          return false;
443        }
444    
445        final LDIFAddChangeRecord r = (LDIFAddChangeRecord) o;
446    
447        final HashSet<Control> c1 = new HashSet<Control>(getControls());
448        final HashSet<Control> c2 = new HashSet<Control>(r.getControls());
449        if (! c1.equals(c2))
450        {
451          return false;
452        }
453    
454        final Entry e1 = new Entry(getDN(), attributes);
455        final Entry e2 = new Entry(r.getDN(), r.attributes);
456        return e1.equals(e2);
457      }
458    
459    
460    
461      /**
462       * {@inheritDoc}
463       */
464      @Override()
465      public void toString(final StringBuilder buffer)
466      {
467        buffer.append("LDIFAddChangeRecord(dn='");
468        buffer.append(getDN());
469        buffer.append("', attrs={");
470    
471        for (int i=0; i < attributes.length; i++)
472        {
473          if (i > 0)
474          {
475            buffer.append(", ");
476          }
477          attributes[i].toString(buffer);
478        }
479        buffer.append('}');
480    
481        final List<Control> controls = getControls();
482        if (! controls.isEmpty())
483        {
484          buffer.append(", controls={");
485    
486          final Iterator<Control> iterator = controls.iterator();
487          while (iterator.hasNext())
488          {
489            iterator.next().toString(buffer);
490            if (iterator.hasNext())
491            {
492              buffer.append(',');
493            }
494          }
495    
496          buffer.append('}');
497        }
498    
499        buffer.append(')');
500      }
501    }