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