001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.protocols.ldap;
028
029import java.io.IOException;
030import java.util.ArrayList;
031import java.util.Iterator;
032import java.util.List;
033
034import org.forgerock.i18n.slf4j.LocalizedLogger;
035import org.forgerock.opendj.io.ASN1Writer;
036import org.forgerock.opendj.ldap.ByteString;
037import org.opends.server.types.RawAttribute;
038import org.opends.server.util.Base64;
039
040import static org.opends.server.protocols.ldap.LDAPConstants.*;
041import static org.opends.server.util.ServerConstants.*;
042import static org.opends.server.util.StaticUtils.*;
043
044/**
045 * This class defines the structures and methods for an LDAP add request
046 * protocol op, which is used to add a new entry to the Directory Server.
047 */
048public class AddRequestProtocolOp
049       extends ProtocolOp
050{
051  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
052
053  /** The set of attributes for this add request. */
054  private List<RawAttribute> attributes;
055
056  /** The DN for this add request. */
057  private ByteString dn;
058
059
060
061  /**
062   * Creates a new LDAP add request protocol op with the specified DN and no
063   * attributes.
064   *
065   * @param  dn  The DN for this add request.
066   */
067  public AddRequestProtocolOp(ByteString dn)
068  {
069    this.dn         = dn;
070    this.attributes = new ArrayList<>();
071  }
072
073
074
075  /**
076   * Creates a new LDAP add request protocol op with the specified DN and set of
077   * attributes.
078   *
079   * @param  dn          The DN for this add request.
080   * @param  attributes  The set of attributes for this add request.
081   */
082  public AddRequestProtocolOp(ByteString dn, List<RawAttribute> attributes)
083  {
084    this.dn = dn;
085
086    if (attributes == null)
087    {
088      this.attributes = new ArrayList<>();
089    }
090    else
091    {
092      this.attributes = attributes;
093    }
094  }
095
096
097
098  /**
099   * Retrieves the DN for this add request.
100   *
101   * @return  The DN for this add request.
102   */
103  public ByteString getDN()
104  {
105    return dn;
106  }
107
108
109  /**
110   * Retrieves the set of attributes for this add request.  The returned list
111   * may be altered by the caller.
112   *
113   * @return  The set of attributes for this add request.
114   */
115  public List<RawAttribute> getAttributes()
116  {
117    return attributes;
118  }
119
120
121
122  /**
123   * Retrieves the BER type for this protocol op.
124   *
125   * @return  The BER type for this protocol op.
126   */
127  @Override
128  public byte getType()
129  {
130    return OP_TYPE_ADD_REQUEST;
131  }
132
133
134
135  /**
136   * Retrieves the name for this protocol op type.
137   *
138   * @return  The name for this protocol op type.
139   */
140  @Override
141  public String getProtocolOpName()
142  {
143    return "Add Request";
144  }
145
146  /**
147   * Writes this protocol op to an ASN.1 output stream.
148   *
149   * @param stream The ASN.1 output stream to write to.
150   * @throws IOException If a problem occurs while writing to the stream.
151   */
152  @Override
153  public void write(ASN1Writer stream) throws IOException
154  {
155    stream.writeStartSequence(OP_TYPE_ADD_REQUEST);
156    stream.writeOctetString(dn);
157
158    // Write the attributes
159    stream.writeStartSequence();
160    for(RawAttribute attr : attributes)
161    {
162      attr.write(stream);
163    }
164    stream.writeEndSequence();
165
166    stream.writeEndSequence();
167  }
168
169
170
171  /**
172   * Appends a string representation of this LDAP protocol op to the provided
173   * buffer.
174   *
175   * @param  buffer  The buffer to which the string should be appended.
176   */
177  @Override
178  public void toString(StringBuilder buffer)
179  {
180    buffer.append("AddRequest(dn=");
181    buffer.append(dn);
182    buffer.append(", attrs={");
183
184    if (! attributes.isEmpty())
185    {
186      Iterator<RawAttribute> iterator = attributes.iterator();
187      iterator.next().toString(buffer);
188
189      while (iterator.hasNext())
190      {
191        buffer.append(", ");
192        iterator.next().toString(buffer);
193      }
194    }
195
196    buffer.append("})");
197  }
198
199
200
201  /**
202   * Appends a multi-line string representation of this LDAP protocol op to the
203   * provided buffer.
204   *
205   * @param  buffer  The buffer to which the information should be appended.
206   * @param  indent  The number of spaces from the margin that the lines should
207   *                 be indented.
208   */
209  @Override
210  public void toString(StringBuilder buffer, int indent)
211  {
212    StringBuilder indentBuf = new StringBuilder(indent);
213    for (int i=0 ; i < indent; i++)
214    {
215      indentBuf.append(' ');
216    }
217
218    buffer.append(indentBuf);
219    buffer.append("Add Request");
220    buffer.append(EOL);
221
222    buffer.append(indentBuf);
223    buffer.append("  DN:  ");
224    buffer.append(dn);
225    buffer.append(EOL);
226
227    buffer.append("  Attributes:");
228    buffer.append(EOL);
229
230    for (RawAttribute attribute : attributes)
231    {
232      attribute.toString(buffer, indent+4);
233    }
234  }
235
236
237
238  /**
239   * Appends an LDIF representation of the entry to the provided buffer.
240   *
241   * @param  buffer      The buffer to which the entry should be appended.
242   * @param  wrapColumn  The column at which long lines should be wrapped.
243   */
244  public void toLDIF(StringBuilder buffer, int wrapColumn)
245  {
246    // Add the DN to the buffer.
247    String dnString;
248    int    colsRemaining;
249    if (needsBase64Encoding(dn))
250    {
251      dnString = Base64.encode(dn);
252      buffer.append("dn:: ");
253
254      colsRemaining = wrapColumn - 5;
255    }
256    else
257    {
258      dnString = dn.toString();
259      buffer.append("dn: ");
260
261      colsRemaining = wrapColumn - 4;
262    }
263
264    int dnLength = dnString.length();
265    if (dnLength <= colsRemaining || colsRemaining <= 0)
266    {
267      buffer.append(dnString);
268      buffer.append(EOL);
269    }
270    else
271    {
272      buffer.append(dnString, 0, colsRemaining);
273      buffer.append(EOL);
274
275      int startPos = colsRemaining;
276      while (dnLength - startPos > wrapColumn - 1)
277      {
278        buffer.append(" ");
279        buffer.append(dnString, startPos, startPos+wrapColumn-1);
280        buffer.append(EOL);
281
282        startPos += wrapColumn-1;
283      }
284
285      if (startPos < dnLength)
286      {
287        buffer.append(" ");
288        buffer.append(dnString.substring(startPos));
289        buffer.append(EOL);
290      }
291    }
292
293
294    // Add the attributes to the buffer.
295    for (RawAttribute a : attributes)
296    {
297      String name       = a.getAttributeType();
298      int    nameLength = name.length();
299
300      for (ByteString v : a.getValues())
301      {
302        String valueString;
303        if (needsBase64Encoding(v))
304        {
305          valueString = Base64.encode(v);
306          buffer.append(name);
307          buffer.append(":: ");
308
309          colsRemaining = wrapColumn - nameLength - 3;
310        }
311        else
312        {
313          valueString = v.toString();
314          buffer.append(name);
315          buffer.append(": ");
316
317          colsRemaining = wrapColumn - nameLength - 2;
318        }
319
320        int valueLength = valueString.length();
321        if (valueLength <= colsRemaining || colsRemaining <= 0)
322        {
323          buffer.append(valueString);
324          buffer.append(EOL);
325        }
326        else
327        {
328          buffer.append(valueString, 0, colsRemaining);
329          buffer.append(EOL);
330
331          int startPos = colsRemaining;
332          while (valueLength - startPos > wrapColumn - 1)
333          {
334            buffer.append(" ");
335            buffer.append(valueString, startPos, startPos+wrapColumn-1);
336            buffer.append(EOL);
337
338            startPos += wrapColumn-1;
339          }
340
341          if (startPos < valueLength)
342          {
343            buffer.append(" ");
344            buffer.append(valueString.substring(startPos));
345            buffer.append(EOL);
346          }
347        }
348      }
349    }
350
351
352    // Make sure to add an extra blank line to ensure that there will be one
353    // between this entry and the next.
354    buffer.append(EOL);
355  }
356}
357