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