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