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 2010 Sun Microsystems, Inc. 015 * Portions copyright 2011-2015 ForgeRock AS. 016 */ 017 018package org.forgerock.opendj.ldap; 019 020import java.util.Collection; 021import java.util.Iterator; 022 023import org.forgerock.i18n.LocalizedIllegalArgumentException; 024import org.forgerock.util.Reject; 025 026import com.forgerock.opendj.util.Iterators; 027 028/** 029 * This class contains methods for creating and manipulating attributes. 030 */ 031public final class Attributes { 032 033 /** 034 * Empty attribute. 035 */ 036 private static final class EmptyAttribute extends AbstractAttribute { 037 038 private final AttributeDescription attributeDescription; 039 040 private EmptyAttribute(final AttributeDescription attributeDescription) { 041 this.attributeDescription = attributeDescription; 042 } 043 044 @Override 045 public boolean add(final ByteString value) { 046 throw new UnsupportedOperationException(); 047 } 048 049 @Override 050 public void clear() { 051 throw new UnsupportedOperationException(); 052 } 053 054 @Override 055 public boolean contains(final Object value) { 056 return false; 057 } 058 059 @Override 060 public AttributeDescription getAttributeDescription() { 061 return attributeDescription; 062 } 063 064 @Override 065 public boolean isEmpty() { 066 return true; 067 } 068 069 @Override 070 public Iterator<ByteString> iterator() { 071 return Iterators.emptyIterator(); 072 } 073 074 @Override 075 public boolean remove(final Object value) { 076 throw new UnsupportedOperationException(); 077 } 078 079 @Override 080 public int size() { 081 return 0; 082 } 083 084 } 085 086 /** 087 * Renamed attribute. 088 */ 089 private static final class RenamedAttribute implements Attribute { 090 091 private final Attribute attribute; 092 private final AttributeDescription attributeDescription; 093 094 private RenamedAttribute(final Attribute attribute, 095 final AttributeDescription attributeDescription) { 096 this.attribute = attribute; 097 this.attributeDescription = attributeDescription; 098 } 099 100 @Override 101 public boolean add(final ByteString value) { 102 return attribute.add(value); 103 } 104 105 @Override 106 public boolean add(final Object... values) { 107 return attribute.add(values); 108 } 109 110 @Override 111 public boolean addAll(final Collection<? extends ByteString> values) { 112 return attribute.addAll(values); 113 } 114 115 @Override 116 public <T> boolean addAll(final Collection<T> values, 117 final Collection<? super T> duplicateValues) { 118 return attribute.addAll(values, duplicateValues); 119 } 120 121 @Override 122 public void clear() { 123 attribute.clear(); 124 } 125 126 @Override 127 public boolean contains(final Object value) { 128 return attribute.contains(value); 129 } 130 131 @Override 132 public boolean containsAll(final Collection<?> values) { 133 return attribute.containsAll(values); 134 } 135 136 @Override 137 public boolean equals(final Object object) { 138 return AbstractAttribute.equals(this, object); 139 } 140 141 @Override 142 public ByteString firstValue() { 143 return attribute.firstValue(); 144 } 145 146 @Override 147 public String firstValueAsString() { 148 return attribute.firstValueAsString(); 149 } 150 151 @Override 152 public AttributeDescription getAttributeDescription() { 153 return attributeDescription; 154 } 155 156 @Override 157 public String getAttributeDescriptionAsString() { 158 return attributeDescription.toString(); 159 } 160 161 @Override 162 public int hashCode() { 163 return AbstractAttribute.hashCode(this); 164 } 165 166 @Override 167 public boolean isEmpty() { 168 return attribute.isEmpty(); 169 } 170 171 @Override 172 public Iterator<ByteString> iterator() { 173 return attribute.iterator(); 174 } 175 176 @Override 177 public AttributeParser parse() { 178 return attribute.parse(); 179 } 180 181 @Override 182 public boolean remove(final Object value) { 183 return attribute.remove(value); 184 } 185 186 @Override 187 public boolean removeAll(final Collection<?> values) { 188 return attribute.removeAll(values); 189 } 190 191 @Override 192 public <T> boolean removeAll(final Collection<T> values, 193 final Collection<? super T> missingValues) { 194 return attribute.removeAll(values, missingValues); 195 } 196 197 @Override 198 public boolean retainAll(final Collection<?> values) { 199 return attribute.retainAll(values); 200 } 201 202 @Override 203 public <T> boolean retainAll(final Collection<T> values, 204 final Collection<? super T> missingValues) { 205 return attribute.retainAll(values, missingValues); 206 } 207 208 @Override 209 public int size() { 210 return attribute.size(); 211 } 212 213 @Override 214 public ByteString[] toArray() { 215 return attribute.toArray(); 216 } 217 218 @Override 219 public <T> T[] toArray(final T[] array) { 220 return attribute.toArray(array); 221 } 222 223 @Override 224 public String toString() { 225 return AbstractAttribute.toString(this); 226 } 227 228 } 229 230 /** 231 * Singleton attribute. 232 */ 233 private static final class SingletonAttribute extends AbstractAttribute { 234 235 private final AttributeDescription attributeDescription; 236 private ByteString normalizedValue; 237 private final ByteString value; 238 239 private SingletonAttribute(final AttributeDescription attributeDescription, 240 final Object value) { 241 this.attributeDescription = attributeDescription; 242 this.value = ByteString.valueOfObject(value); 243 } 244 245 @Override 246 public boolean add(final ByteString value) { 247 throw new UnsupportedOperationException(); 248 } 249 250 @Override 251 public void clear() { 252 throw new UnsupportedOperationException(); 253 } 254 255 @Override 256 public boolean contains(final Object value) { 257 final ByteString normalizedValue = normalizeValue(this, ByteString.valueOfObject(value)); 258 return normalizedSingleValue().equals(normalizedValue); 259 } 260 261 @Override 262 public AttributeDescription getAttributeDescription() { 263 return attributeDescription; 264 } 265 266 @Override 267 public boolean isEmpty() { 268 return false; 269 } 270 271 @Override 272 public Iterator<ByteString> iterator() { 273 return Iterators.singletonIterator(value); 274 } 275 276 @Override 277 public boolean remove(final Object value) { 278 throw new UnsupportedOperationException(); 279 } 280 281 @Override 282 public int size() { 283 return 1; 284 } 285 286 /** Lazily computes the normalized single value. */ 287 private ByteString normalizedSingleValue() { 288 if (normalizedValue == null) { 289 normalizedValue = normalizeValue(this, value); 290 } 291 return normalizedValue; 292 } 293 294 } 295 296 /** 297 * Unmodifiable attribute. 298 */ 299 private static final class UnmodifiableAttribute implements Attribute { 300 301 private final Attribute attribute; 302 303 private UnmodifiableAttribute(final Attribute attribute) { 304 this.attribute = attribute; 305 } 306 307 @Override 308 public boolean add(final ByteString value) { 309 throw new UnsupportedOperationException(); 310 } 311 312 @Override 313 public boolean add(final Object... values) { 314 throw new UnsupportedOperationException(); 315 } 316 317 @Override 318 public boolean addAll(final Collection<? extends ByteString> values) { 319 throw new UnsupportedOperationException(); 320 } 321 322 @Override 323 public <T> boolean addAll(final Collection<T> values, 324 final Collection<? super T> duplicateValues) { 325 throw new UnsupportedOperationException(); 326 } 327 328 @Override 329 public void clear() { 330 throw new UnsupportedOperationException(); 331 } 332 333 @Override 334 public boolean contains(final Object value) { 335 return attribute.contains(value); 336 } 337 338 @Override 339 public boolean containsAll(final Collection<?> values) { 340 return attribute.containsAll(values); 341 } 342 343 @Override 344 public boolean equals(final Object object) { 345 return object == this || attribute.equals(object); 346 } 347 348 @Override 349 public ByteString firstValue() { 350 return attribute.firstValue(); 351 } 352 353 @Override 354 public String firstValueAsString() { 355 return attribute.firstValueAsString(); 356 } 357 358 @Override 359 public AttributeDescription getAttributeDescription() { 360 return attribute.getAttributeDescription(); 361 } 362 363 @Override 364 public String getAttributeDescriptionAsString() { 365 return attribute.getAttributeDescriptionAsString(); 366 } 367 368 @Override 369 public int hashCode() { 370 return attribute.hashCode(); 371 } 372 373 @Override 374 public boolean isEmpty() { 375 return attribute.isEmpty(); 376 } 377 378 @Override 379 public Iterator<ByteString> iterator() { 380 return Iterators.unmodifiableIterator(attribute.iterator()); 381 } 382 383 @Override 384 public AttributeParser parse() { 385 return attribute.parse(); 386 } 387 388 @Override 389 public boolean remove(final Object value) { 390 throw new UnsupportedOperationException(); 391 } 392 393 @Override 394 public boolean removeAll(final Collection<?> values) { 395 throw new UnsupportedOperationException(); 396 } 397 398 @Override 399 public <T> boolean removeAll(final Collection<T> values, 400 final Collection<? super T> missingValues) { 401 throw new UnsupportedOperationException(); 402 } 403 404 @Override 405 public boolean retainAll(final Collection<?> values) { 406 throw new UnsupportedOperationException(); 407 } 408 409 @Override 410 public <T> boolean retainAll(final Collection<T> values, 411 final Collection<? super T> missingValues) { 412 throw new UnsupportedOperationException(); 413 } 414 415 @Override 416 public int size() { 417 return attribute.size(); 418 } 419 420 @Override 421 public ByteString[] toArray() { 422 return attribute.toArray(); 423 } 424 425 @Override 426 public <T> T[] toArray(final T[] array) { 427 return attribute.toArray(array); 428 } 429 430 @Override 431 public String toString() { 432 return attribute.toString(); 433 } 434 } 435 436 /** 437 * Returns a read-only empty attribute having the specified attribute 438 * description. Attempts to modify the returned attribute either directly, 439 * or indirectly via an iterator, result in an 440 * {@code UnsupportedOperationException}. 441 * 442 * @param attributeDescription 443 * The attribute description. 444 * @return The empty attribute. 445 * @throws NullPointerException 446 * If {@code attributeDescription} was {@code null}. 447 */ 448 public static Attribute emptyAttribute(final AttributeDescription attributeDescription) { 449 return new EmptyAttribute(attributeDescription); 450 } 451 452 /** 453 * Returns a read-only empty attribute having the specified attribute 454 * description. The attribute description will be decoded using the default 455 * schema. Attempts to modify the returned attribute either directly, or 456 * indirectly via an iterator, result in an 457 * {@code UnsupportedOperationException}. 458 * 459 * @param attributeDescription 460 * The attribute description. 461 * @return The empty attribute. 462 * @throws LocalizedIllegalArgumentException 463 * If {@code attributeDescription} could not be decoded using 464 * the default schema. 465 * @throws NullPointerException 466 * If {@code attributeDescription} was {@code null}. 467 */ 468 public static Attribute emptyAttribute(final String attributeDescription) { 469 return emptyAttribute(AttributeDescription.valueOf(attributeDescription)); 470 } 471 472 /** 473 * Returns a view of {@code attribute} having a different attribute 474 * description. All operations on the returned attribute "pass-through" to 475 * the underlying attribute. 476 * 477 * @param attribute 478 * The attribute to be renamed. 479 * @param attributeDescription 480 * The new attribute description for {@code attribute}. 481 * @return A renamed view of {@code attribute}. 482 * @throws NullPointerException 483 * If {@code attribute} or {@code attributeDescription} was 484 * {@code null}. 485 */ 486 public static Attribute renameAttribute(final Attribute attribute, 487 final AttributeDescription attributeDescription) { 488 Reject.ifNull(attribute, attributeDescription); 489 490 // Optimize for the case where no renaming is required. 491 if (attribute.getAttributeDescription() == attributeDescription) { 492 return attribute; 493 } else { 494 return new RenamedAttribute(attribute, attributeDescription); 495 } 496 } 497 498 /** 499 * Returns a view of {@code attribute} having a different attribute 500 * description. All operations on the returned attribute "pass-through" to 501 * the underlying attribute. The attribute description will be decoded using 502 * the default schema. 503 * 504 * @param attribute 505 * The attribute to be renamed. 506 * @param attributeDescription 507 * The new attribute description for {@code attribute}. 508 * @return A renamed view of {@code attribute}. 509 * @throws LocalizedIllegalArgumentException 510 * If {@code attributeDescription} could not be decoded using 511 * the default schema. 512 * @throws NullPointerException 513 * If {@code attribute} or {@code attributeDescription} was 514 * {@code null}. 515 */ 516 public static Attribute renameAttribute(final Attribute attribute, final String attributeDescription) { 517 Reject.ifNull(attribute, attributeDescription); 518 return renameAttribute(attribute, AttributeDescription.valueOf(attributeDescription)); 519 } 520 521 /** 522 * Returns a read-only single-valued attribute having the specified 523 * attribute description and value. Attempts to modify the returned 524 * attribute either directly, or indirectly via an iterator, result in an 525 * {@code UnsupportedOperationException}. 526 * <p> 527 * If {@code value} is not an instance of {@code ByteString} then it will be 528 * converted using the {@link ByteString#valueOfObject(Object)} method. 529 * 530 * @param attributeDescription 531 * The attribute description. 532 * @param value 533 * The single attribute value. 534 * @return The single-valued attribute. 535 * @throws NullPointerException 536 * If {@code attributeDescription} or {@code value} was 537 * {@code null}. 538 */ 539 public static Attribute singletonAttribute(final AttributeDescription attributeDescription, final Object value) { 540 return new SingletonAttribute(attributeDescription, value); 541 } 542 543 /** 544 * Returns a read-only single-valued attribute having the specified 545 * attribute description. The attribute description will be decoded using 546 * the default schema. Attempts to modify the returned attribute either 547 * directly, or indirectly via an iterator, result in an 548 * {@code UnsupportedOperationException}. 549 * <p> 550 * If {@code value} is not an instance of {@code ByteString} then it will be 551 * converted using the {@link ByteString#valueOfObject(Object)} method. 552 * 553 * @param attributeDescription 554 * The attribute description. 555 * @param value 556 * The single attribute value. 557 * @return The single-valued attribute. 558 * @throws LocalizedIllegalArgumentException 559 * If {@code attributeDescription} could not be decoded using 560 * the default schema. 561 * @throws NullPointerException 562 * If {@code attributeDescription} or {@code value} was 563 * {@code null}. 564 */ 565 public static Attribute singletonAttribute(final String attributeDescription, final Object value) { 566 return singletonAttribute(AttributeDescription.valueOf(attributeDescription), value); 567 } 568 569 /** 570 * Returns a read-only view of {@code attribute}. Query operations on the 571 * returned attribute "read-through" to the underlying attribute, and 572 * attempts to modify the returned attribute either directly or indirectly 573 * via an iterator result in an {@code UnsupportedOperationException}. 574 * 575 * @param attribute 576 * The attribute for which a read-only view is to be returned. 577 * @return A read-only view of {@code attribute}. 578 * @throws NullPointerException 579 * If {@code attribute} was {@code null}. 580 */ 581 public static Attribute unmodifiableAttribute(final Attribute attribute) { 582 if (attribute instanceof UnmodifiableAttribute) { 583 return attribute; 584 } 585 return new UnmodifiableAttribute(attribute); 586 } 587 588 /** Prevent instantiation. */ 589 private Attributes() { 590 // Nothing to do. 591 } 592}