001/*
002 * Copyright 2007-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2019 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 LDIFAddChangeRecord duplicate(final Control... controls)
288  {
289    return new LDIFAddChangeRecord(getDN(), attributes,
290         StaticUtils.toList(controls));
291  }
292
293
294
295  /**
296   * {@inheritDoc}
297   */
298  @Override()
299  public LDAPResult processChange(final LDAPInterface connection,
300                                  final boolean includeControls)
301         throws LDAPException
302  {
303    return connection.add(toAddRequest(includeControls));
304  }
305
306
307
308  /**
309   * {@inheritDoc}
310   */
311  @Override()
312  public String[] toLDIF(final int wrapColumn)
313  {
314    List<String> ldifLines = new ArrayList<>(2*attributes.length);
315    encodeNameAndValue("dn", new ASN1OctetString(getDN()), ldifLines);
316
317    for (final Control c : getControls())
318    {
319      encodeNameAndValue("control", encodeControlString(c), ldifLines);
320    }
321
322    ldifLines.add("changetype: add");
323
324    for (final Attribute a : attributes)
325    {
326      final String name = a.getName();
327      for (final ASN1OctetString value : a.getRawValues())
328      {
329        encodeNameAndValue(name, value, ldifLines);
330      }
331    }
332
333    if (wrapColumn > 2)
334    {
335      ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines);
336    }
337
338    final String[] ldifArray = new String[ldifLines.size()];
339    ldifLines.toArray(ldifArray);
340    return ldifArray;
341  }
342
343
344
345  /**
346   * {@inheritDoc}
347   */
348  @Override()
349  public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn)
350  {
351    LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer,
352         wrapColumn);
353    buffer.append(StaticUtils.EOL_BYTES);
354
355    for (final Control c : getControls())
356    {
357      LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer,
358           wrapColumn);
359      buffer.append(StaticUtils.EOL_BYTES);
360    }
361
362    LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"),
363                                  buffer, wrapColumn);
364    buffer.append(StaticUtils.EOL_BYTES);
365
366    for (final Attribute a : attributes)
367    {
368      final String name = a.getName();
369      for (final ASN1OctetString value : a.getRawValues())
370      {
371        LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
372        buffer.append(StaticUtils.EOL_BYTES);
373      }
374    }
375  }
376
377
378
379  /**
380   * {@inheritDoc}
381   */
382  @Override()
383  public void toLDIFString(final StringBuilder buffer, final int wrapColumn)
384  {
385    LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer,
386         wrapColumn);
387    buffer.append(StaticUtils.EOL);
388
389    for (final Control c : getControls())
390    {
391      LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer,
392           wrapColumn);
393      buffer.append(StaticUtils.EOL);
394    }
395
396    LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"),
397                                  buffer, wrapColumn);
398    buffer.append(StaticUtils.EOL);
399
400    for (final Attribute a : attributes)
401    {
402      final String name = a.getName();
403      for (final ASN1OctetString value : a.getRawValues())
404      {
405        LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
406        buffer.append(StaticUtils.EOL);
407      }
408    }
409  }
410
411
412
413  /**
414   * {@inheritDoc}
415   */
416  @Override()
417  public int hashCode()
418  {
419    try
420    {
421      int hashCode = getParsedDN().hashCode();
422      for (final Attribute a : attributes)
423      {
424        hashCode += a.hashCode();
425      }
426
427      return hashCode;
428    }
429    catch (final Exception e)
430    {
431      Debug.debugException(e);
432      return new Entry(getDN(), attributes).hashCode();
433    }
434  }
435
436
437
438  /**
439   * {@inheritDoc}
440   */
441  @Override()
442  public boolean equals(final Object o)
443  {
444    if (o == null)
445    {
446      return false;
447    }
448
449    if (o == this)
450    {
451      return true;
452    }
453
454    if (! (o instanceof LDIFAddChangeRecord))
455    {
456      return false;
457    }
458
459    final LDIFAddChangeRecord r = (LDIFAddChangeRecord) o;
460
461    final HashSet<Control> c1 = new HashSet<>(getControls());
462    final HashSet<Control> c2 = new HashSet<>(r.getControls());
463    if (! c1.equals(c2))
464    {
465      return false;
466    }
467
468    final Entry e1 = new Entry(getDN(), attributes);
469    final Entry e2 = new Entry(r.getDN(), r.attributes);
470    return e1.equals(e2);
471  }
472
473
474
475  /**
476   * {@inheritDoc}
477   */
478  @Override()
479  public void toString(final StringBuilder buffer)
480  {
481    buffer.append("LDIFAddChangeRecord(dn='");
482    buffer.append(getDN());
483    buffer.append("', attrs={");
484
485    for (int i=0; i < attributes.length; i++)
486    {
487      if (i > 0)
488      {
489        buffer.append(", ");
490      }
491      attributes[i].toString(buffer);
492    }
493    buffer.append('}');
494
495    final List<Control> controls = getControls();
496    if (! controls.isEmpty())
497    {
498      buffer.append(", controls={");
499
500      final Iterator<Control> iterator = controls.iterator();
501      while (iterator.hasNext())
502      {
503        iterator.next().toString(buffer);
504        if (iterator.hasNext())
505        {
506          buffer.append(',');
507        }
508      }
509
510      buffer.append('}');
511    }
512
513    buffer.append(')');
514  }
515}