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