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}