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