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