001/* 002 * Copyright 2007-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldif; 037 038 039 040import java.util.ArrayList; 041import java.util.Collection; 042import java.util.HashSet; 043import java.util.Iterator; 044import java.util.List; 045 046import com.unboundid.asn1.ASN1OctetString; 047import com.unboundid.ldap.sdk.AddRequest; 048import com.unboundid.ldap.sdk.Attribute; 049import com.unboundid.ldap.sdk.ChangeType; 050import com.unboundid.ldap.sdk.Control; 051import com.unboundid.ldap.sdk.Entry; 052import com.unboundid.ldap.sdk.LDAPException; 053import com.unboundid.ldap.sdk.LDAPInterface; 054import com.unboundid.ldap.sdk.LDAPResult; 055import com.unboundid.util.ByteStringBuffer; 056import com.unboundid.util.Debug; 057import com.unboundid.util.NotMutable; 058import com.unboundid.util.StaticUtils; 059import com.unboundid.util.ThreadSafety; 060import com.unboundid.util.ThreadSafetyLevel; 061import com.unboundid.util.Validator; 062 063 064 065/** 066 * This class defines an LDIF add change record, which can be used to represent 067 * an LDAP add request. See the documentation for the {@link LDIFChangeRecord} 068 * class for an example demonstrating the process for interacting with LDIF 069 * change records. 070 */ 071@NotMutable() 072@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 073public final class LDIFAddChangeRecord 074 extends LDIFChangeRecord 075{ 076 /** 077 * The serial version UID for this serializable class. 078 */ 079 private static final long serialVersionUID = 4722916031463878423L; 080 081 082 083 // The set of attributes for this add change record. 084 private final Attribute[] attributes; 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 */ 096 public LDIFAddChangeRecord(final String dn, final Attribute... attributes) 097 { 098 this(dn, attributes, null); 099 } 100 101 102 103 /** 104 * Creates a new LDIF add change record with the provided DN and attributes. 105 * 106 * @param dn The DN for this LDIF add change record. It must not be 107 * {@code null}. 108 * @param attributes The set of attributes for this LDIF add change record. 109 * It must not be {@code null} or empty. 110 * @param controls The set of controls for this LDIF add change record. 111 * It may be {@code null} or empty if there are no 112 * controls. 113 */ 114 public LDIFAddChangeRecord(final String dn, final Attribute[] attributes, 115 final List<Control> controls) 116 { 117 super(dn, controls); 118 119 Validator.ensureNotNull(attributes); 120 Validator.ensureTrue(attributes.length > 0, 121 "LDIFAddChangeRecord.attributes must not be empty."); 122 123 this.attributes = attributes; 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 */ 136 public LDIFAddChangeRecord(final String dn, final List<Attribute> attributes) 137 { 138 this(dn, attributes, null); 139 } 140 141 142 143 /** 144 * Creates a new LDIF add change record with the provided DN and attributes. 145 * 146 * @param dn The DN for this LDIF add change record. It must not be 147 * {@code null}. 148 * @param attributes The set of attributes for this LDIF add change record. 149 * It must not be {@code null} or empty. 150 * @param controls The set of controls for this LDIF add change record. 151 * It may be {@code null} or empty if there are no 152 * controls. 153 */ 154 public LDIFAddChangeRecord(final String dn, final List<Attribute> attributes, 155 final List<Control> controls) 156 { 157 super(dn, controls); 158 159 Validator.ensureNotNull(attributes); 160 Validator.ensureFalse(attributes.isEmpty(), 161 "LDIFAddChangeRecord.attributes must not be empty."); 162 163 this.attributes = new Attribute[attributes.size()]; 164 attributes.toArray(this.attributes); 165 } 166 167 168 169 /** 170 * Creates a new LDIF add change record from the provided entry. 171 * 172 * @param entry The entry to use to create this LDIF add change record. It 173 * must not be {@code null}. 174 */ 175 public LDIFAddChangeRecord(final Entry entry) 176 { 177 this(entry, null); 178 } 179 180 181 182 /** 183 * Creates a new LDIF add change record from the provided entry. 184 * 185 * @param entry The entry to use to create this LDIF add change record. 186 * It must not be {@code null}. 187 * @param controls The set of controls for this LDIF add change record. It 188 * may be {@code null} or empty if there are no controls. 189 */ 190 public LDIFAddChangeRecord(final Entry entry, final List<Control> controls) 191 { 192 super(entry.getDN(), controls); 193 194 final Collection<Attribute> attrs = entry.getAttributes(); 195 attributes = new Attribute[attrs.size()]; 196 197 final Iterator<Attribute> iterator = attrs.iterator(); 198 for (int i=0; i < attributes.length; i++) 199 { 200 attributes[i] = iterator.next(); 201 } 202 } 203 204 205 206 /** 207 * Creates a new LDIF add change record from the provided add request. 208 * 209 * @param addRequest The add request to use to create this LDIF add change 210 * record. It must not be {@code null}. 211 */ 212 public LDIFAddChangeRecord(final AddRequest addRequest) 213 { 214 super(addRequest.getDN(), addRequest.getControlList()); 215 216 final List<Attribute> attrs = addRequest.getAttributes(); 217 attributes = new Attribute[attrs.size()]; 218 219 final Iterator<Attribute> iterator = attrs.iterator(); 220 for (int i=0; i < attributes.length; i++) 221 { 222 attributes[i] = iterator.next(); 223 } 224 } 225 226 227 228 /** 229 * Retrieves the set of attributes for this add change record. 230 * 231 * @return The set of attributes for this add change record. 232 */ 233 public Attribute[] getAttributes() 234 { 235 return attributes; 236 } 237 238 239 240 /** 241 * Retrieves the entry that would be created by this add change record. 242 * 243 * @return The entry that would be created by this add change record. 244 */ 245 public Entry getEntryToAdd() 246 { 247 return new Entry(getDN(), attributes); 248 } 249 250 251 252 /** 253 * Creates an add request from this LDIF add change record. Any controls 254 * included in this change record will be included in the request. 255 * 256 * @return The add request created from this LDIF add change record. 257 */ 258 public AddRequest toAddRequest() 259 { 260 return toAddRequest(true); 261 } 262 263 264 265 /** 266 * Creates an add request from this LDIF add change record, optionally 267 * including any change record controls in the request. 268 * 269 * @param includeControls Indicates whether to include any controls in the 270 * request. 271 * 272 * @return The add request created from this LDIF add change record. 273 */ 274 public AddRequest toAddRequest(final boolean includeControls) 275 { 276 final AddRequest addRequest = new AddRequest(getDN(), attributes); 277 if (includeControls) 278 { 279 addRequest.setControls(getControls()); 280 } 281 282 return addRequest; 283 } 284 285 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override() 291 public ChangeType getChangeType() 292 { 293 return ChangeType.ADD; 294 } 295 296 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override() 302 public LDIFAddChangeRecord duplicate(final Control... controls) 303 { 304 return new LDIFAddChangeRecord(getDN(), attributes, 305 StaticUtils.toList(controls)); 306 } 307 308 309 310 /** 311 * {@inheritDoc} 312 */ 313 @Override() 314 public LDAPResult processChange(final LDAPInterface connection, 315 final boolean includeControls) 316 throws LDAPException 317 { 318 return connection.add(toAddRequest(includeControls)); 319 } 320 321 322 323 /** 324 * {@inheritDoc} 325 */ 326 @Override() 327 public String[] toLDIF(final int wrapColumn) 328 { 329 List<String> ldifLines = new ArrayList<>(2*attributes.length); 330 encodeNameAndValue("dn", new ASN1OctetString(getDN()), ldifLines); 331 332 for (final Control c : getControls()) 333 { 334 encodeNameAndValue("control", encodeControlString(c), ldifLines); 335 } 336 337 ldifLines.add("changetype: add"); 338 339 for (final Attribute a : attributes) 340 { 341 final String name = a.getName(); 342 for (final ASN1OctetString value : a.getRawValues()) 343 { 344 encodeNameAndValue(name, value, ldifLines); 345 } 346 } 347 348 if (wrapColumn > 2) 349 { 350 ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines); 351 } 352 353 final String[] ldifArray = new String[ldifLines.size()]; 354 ldifLines.toArray(ldifArray); 355 return ldifArray; 356 } 357 358 359 360 /** 361 * {@inheritDoc} 362 */ 363 @Override() 364 public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn) 365 { 366 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 367 wrapColumn); 368 buffer.append(StaticUtils.EOL_BYTES); 369 370 for (final Control c : getControls()) 371 { 372 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 373 wrapColumn); 374 buffer.append(StaticUtils.EOL_BYTES); 375 } 376 377 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"), 378 buffer, wrapColumn); 379 buffer.append(StaticUtils.EOL_BYTES); 380 381 for (final Attribute a : attributes) 382 { 383 final String name = a.getName(); 384 for (final ASN1OctetString value : a.getRawValues()) 385 { 386 LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn); 387 buffer.append(StaticUtils.EOL_BYTES); 388 } 389 } 390 } 391 392 393 394 /** 395 * {@inheritDoc} 396 */ 397 @Override() 398 public void toLDIFString(final StringBuilder buffer, final int wrapColumn) 399 { 400 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(getDN()), buffer, 401 wrapColumn); 402 buffer.append(StaticUtils.EOL); 403 404 for (final Control c : getControls()) 405 { 406 LDIFWriter.encodeNameAndValue("control", encodeControlString(c), buffer, 407 wrapColumn); 408 buffer.append(StaticUtils.EOL); 409 } 410 411 LDIFWriter.encodeNameAndValue("changetype", new ASN1OctetString("add"), 412 buffer, wrapColumn); 413 buffer.append(StaticUtils.EOL); 414 415 for (final Attribute a : attributes) 416 { 417 final String name = a.getName(); 418 for (final ASN1OctetString value : a.getRawValues()) 419 { 420 LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn); 421 buffer.append(StaticUtils.EOL); 422 } 423 } 424 } 425 426 427 428 /** 429 * {@inheritDoc} 430 */ 431 @Override() 432 public int hashCode() 433 { 434 try 435 { 436 int hashCode = getParsedDN().hashCode(); 437 for (final Attribute a : attributes) 438 { 439 hashCode += a.hashCode(); 440 } 441 442 return hashCode; 443 } 444 catch (final Exception e) 445 { 446 Debug.debugException(e); 447 return new Entry(getDN(), attributes).hashCode(); 448 } 449 } 450 451 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override() 457 public boolean equals(final Object o) 458 { 459 if (o == null) 460 { 461 return false; 462 } 463 464 if (o == this) 465 { 466 return true; 467 } 468 469 if (! (o instanceof LDIFAddChangeRecord)) 470 { 471 return false; 472 } 473 474 final LDIFAddChangeRecord r = (LDIFAddChangeRecord) o; 475 476 final HashSet<Control> c1 = new HashSet<>(getControls()); 477 final HashSet<Control> c2 = new HashSet<>(r.getControls()); 478 if (! c1.equals(c2)) 479 { 480 return false; 481 } 482 483 final Entry e1 = new Entry(getDN(), attributes); 484 final Entry e2 = new Entry(r.getDN(), r.attributes); 485 return e1.equals(e2); 486 } 487 488 489 490 /** 491 * {@inheritDoc} 492 */ 493 @Override() 494 public void toString(final StringBuilder buffer) 495 { 496 buffer.append("LDIFAddChangeRecord(dn='"); 497 buffer.append(getDN()); 498 buffer.append("', attrs={"); 499 500 for (int i=0; i < attributes.length; i++) 501 { 502 if (i > 0) 503 { 504 buffer.append(", "); 505 } 506 attributes[i].toString(buffer); 507 } 508 buffer.append('}'); 509 510 final List<Control> controls = getControls(); 511 if (! controls.isEmpty()) 512 { 513 buffer.append(", controls={"); 514 515 final Iterator<Control> iterator = controls.iterator(); 516 while (iterator.hasNext()) 517 { 518 iterator.next().toString(buffer); 519 if (iterator.hasNext()) 520 { 521 buffer.append(','); 522 } 523 } 524 525 buffer.append('}'); 526 } 527 528 buffer.append(')'); 529 } 530}