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 */
021package com.unboundid.ldif;
022
023
024
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.List;
030
031import com.unboundid.asn1.ASN1OctetString;
032import com.unboundid.ldap.sdk.AddRequest;
033import com.unboundid.ldap.sdk.Attribute;
034import com.unboundid.ldap.sdk.ChangeType;
035import com.unboundid.ldap.sdk.Control;
036import com.unboundid.ldap.sdk.Entry;
037import com.unboundid.ldap.sdk.LDAPException;
038import com.unboundid.ldap.sdk.LDAPInterface;
039import com.unboundid.ldap.sdk.LDAPResult;
040import com.unboundid.util.ByteStringBuffer;
041import com.unboundid.util.NotMutable;
042import com.unboundid.util.ThreadSafety;
043import com.unboundid.util.ThreadSafetyLevel;
044
045import static com.unboundid.util.Debug.*;
046import static com.unboundid.util.StaticUtils.*;
047import 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)
059public 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}