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 2012-2015 ForgeRock AS. 025 */ 026package org.opends.server.types; 027 028import java.util.Arrays; 029import java.util.Collection; 030import java.util.LinkedHashSet; 031import java.util.NoSuchElementException; 032import java.util.Set; 033 034import org.forgerock.opendj.ldap.ByteString; 035import org.forgerock.opendj.ldap.Functions; 036import org.forgerock.opendj.ldap.GeneralizedTime; 037import org.forgerock.opendj.ldap.schema.Schema; 038import org.forgerock.util.Function; 039import org.forgerock.util.promise.NeverThrowsException; 040 041 042/** 043 * A fluent API for parsing attributes as different types of object. An 044 * attribute parser is obtained from an entry using the method 045 * {@link Entry#parseAttribute} or from an attribute using 046 * {@link Attribute#parse}. 047 * <p> 048 * Methods throw an {@code IllegalArgumentException} when a value cannot be 049 * parsed (e.g. because its syntax is invalid). Methods which return a 050 * {@code Set} always return a modifiable non-{@code null} result, even if the 051 * attribute is {@code null} or empty. 052 * <p> 053 * Examples: 054 * 055 * <pre> 056 * Entry entry = ...; 057 * 058 * Calendar timestamp = entry.parseAttribute("createTimestamp").asCalendar(); 059 * boolean isEnabled = entry.parseAttribute("enabled").asBoolean(false); 060 * 061 * Entry group = ...; 062 * Schema schema = ...; 063 * 064 * Set<DN> members = group.parseAttribute("member").usingSchema(schema).asSetOfDN(); 065 * </pre> 066 * 067 * @see Entry#parseAttribute 068 * @see Attribute#parse 069 */ 070public final class AttributeParser { 071 // TODO: enums, filters, rdns? 072 073 private static final AttributeParser NULL_INSTANCE = new AttributeParser(null); 074 075 /** 076 * Returns an attribute parser for the provided attribute. {@code null} 077 * attributes are permitted and will be treated as if an empty attribute was 078 * provided. 079 * 080 * @param attribute 081 * The attribute to be parsed, which may be {@code null}. 082 * @return The attribute parser. 083 */ 084 public static AttributeParser parseAttribute(final Attribute attribute) { 085 return isEmpty(attribute) ? NULL_INSTANCE : new AttributeParser(attribute); 086 } 087 088 private static boolean isEmpty(final Attribute attribute) { 089 return attribute == null || attribute.isEmpty(); 090 } 091 092 private final Attribute attribute; 093 private Schema schema; 094 095 private AttributeParser(final Attribute attribute) { 096 this.attribute = attribute; 097 } 098 099 /** 100 * Returns the first value decoded as a {@code T} using the provided 101 * {@link Function}, or {@code null} if the attribute does not contain any 102 * values. 103 * 104 * @param <T> 105 * The type of the value to be decoded. 106 * @param f 107 * The function which should be used to decode the value. 108 * @return The first value decoded as a {@code T}. 109 */ 110 public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f) { 111 return as(f, null); 112 } 113 114 /** 115 * Returns the first value decoded as a {@code T} using the provided 116 * {@link Function}, or {@code defaultValue} if the attribute does not 117 * contain any values. 118 * 119 * @param <T> 120 * The type of the value to be decoded. 121 * @param f 122 * The function which should be used to decode the value. 123 * @param defaultValue 124 * The default value to return if the attribute is empty. 125 * @return The first value decoded as a {@code T}. 126 */ 127 public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f, final T defaultValue) { 128 if (!isEmpty(attribute)) { 129 return f.apply(attribute.iterator().next()); 130 } else { 131 return defaultValue; 132 } 133 } 134 135 /** 136 * Returns the first value decoded as a boolean, or {@code null} if the 137 * attribute does not contain any values. 138 * 139 * @return The first value decoded as a boolean. 140 */ 141 public Boolean asBoolean() { 142 return isEmpty(attribute) ? null : asBoolean(false /* ignored */); 143 } 144 145 /** 146 * Returns the first value decoded as an {@code Boolean}, or 147 * {@code defaultValue} if the attribute does not contain any values. 148 * 149 * @param defaultValue 150 * The default value to return if the attribute is empty. 151 * @return The first value decoded as an {@code Boolean}. 152 */ 153 public boolean asBoolean(final boolean defaultValue) { 154 return as(Functions.byteStringToBoolean(), defaultValue); 155 } 156 157 /** 158 * Returns the first value, or {@code null} if the attribute does not 159 * contain any values. 160 * 161 * @return The first value. 162 */ 163 public ByteString asByteString() { 164 return asByteString(null); 165 } 166 167 /** 168 * Returns the first value, or {@code defaultValue} if the attribute does 169 * not contain any values. 170 * 171 * @param defaultValue 172 * The default value to return if the attribute is empty. 173 * @return The first value. 174 */ 175 public ByteString asByteString(final ByteString defaultValue) { 176 return as(Functions.<ByteString> identityFunction(), defaultValue); 177 } 178 179 /** 180 * Returns the first value decoded as a {@code GeneralizedTime} using the 181 * generalized time syntax, or {@code null} if the attribute does not 182 * contain any values. 183 * 184 * @return The first value decoded as a {@code GeneralizedTime}. 185 */ 186 public GeneralizedTime asGeneralizedTime() { 187 return asGeneralizedTime(null); 188 } 189 190 /** 191 * Returns the first value decoded as an {@code GeneralizedTime} using the 192 * generalized time syntax, or {@code defaultValue} if the attribute does 193 * not contain any values. 194 * 195 * @param defaultValue 196 * The default value to return if the attribute is empty. 197 * @return The first value decoded as an {@code GeneralizedTime}. 198 */ 199 public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) { 200 return as(Functions.byteStringToGeneralizedTime(), defaultValue); 201 } 202 203 /** 204 * Returns the first value decoded as an {@code Integer}, or {@code null} if 205 * the attribute does not contain any values. 206 * 207 * @return The first value decoded as an {@code Integer}. 208 */ 209 public Integer asInteger() { 210 return isEmpty(attribute) ? null : asInteger(0 /* ignored */); 211 } 212 213 /** 214 * Returns the first value decoded as an {@code Integer}, or 215 * {@code defaultValue} if the attribute does not contain any values. 216 * 217 * @param defaultValue 218 * The default value to return if the attribute is empty. 219 * @return The first value decoded as an {@code Integer}. 220 */ 221 public int asInteger(final int defaultValue) { 222 return as(Functions.byteStringToInteger(), defaultValue); 223 } 224 225 /** 226 * Returns the first value decoded as a {@code Long}, or {@code null} if the 227 * attribute does not contain any values. 228 * 229 * @return The first value decoded as a {@code Long}. 230 */ 231 public Long asLong() { 232 return isEmpty(attribute) ? null : asLong(0L /* ignored */); 233 } 234 235 /** 236 * Returns the first value decoded as a {@code Long}, or 237 * {@code defaultValue} if the attribute does not contain any values. 238 * 239 * @param defaultValue 240 * The default value to return if the attribute is empty. 241 * @return The first value decoded as a {@code Long}. 242 */ 243 public long asLong(final long defaultValue) { 244 return as(Functions.byteStringToLong(), defaultValue); 245 } 246 247 /** 248 * Returns the values decoded as a set of {@code T}s using the provided 249 * {@link Function}, or {@code defaultValues} if the attribute does not 250 * contain any values. 251 * 252 * @param <T> 253 * The type of the values to be decoded. 254 * @param f 255 * The function which should be used to decode values. 256 * @param defaultValues 257 * The default values to return if the attribute is empty. 258 * @return The values decoded as a set of {@code T}s. 259 */ 260 public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f, 261 final Collection<? extends T> defaultValues) { 262 if (!isEmpty(attribute)) { 263 final LinkedHashSet<T> result = new LinkedHashSet<>(attribute.size()); 264 for (final ByteString v : attribute) { 265 result.add(f.apply(v)); 266 } 267 return result; 268 } else if (defaultValues != null) { 269 return new LinkedHashSet<>(defaultValues); 270 } else { 271 return new LinkedHashSet<>(0); 272 } 273 } 274 275 /** 276 * Returns the values decoded as a set of {@code T}s using the provided 277 * {@link Function}, or {@code defaultValues} if the attribute does not 278 * contain any values. 279 * 280 * @param <T> 281 * The type of the values to be decoded. 282 * @param f 283 * The function which should be used to decode values. 284 * @param defaultValues 285 * The default values to return if the attribute is empty. 286 * @return The values decoded as a set of {@code T}s. 287 */ 288 public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f, 289 final T... defaultValues) { 290 return asSetOf(f, Arrays.asList(defaultValues)); 291 } 292 293 /** 294 * Returns the values decoded as a set of {@code Boolean}s, or 295 * {@code defaultValues} if the attribute does not contain any values. 296 * 297 * @param defaultValues 298 * The default values to return if the attribute is empty. 299 * @return The values decoded as a set of {@code Boolean}s. 300 */ 301 public Set<Boolean> asSetOfBoolean(final Boolean... defaultValues) { 302 return asSetOfBoolean(Arrays.asList(defaultValues)); 303 } 304 305 /** 306 * Returns the values decoded as a set of {@code Boolean}s, or 307 * {@code defaultValues} if the attribute does not contain any values. 308 * 309 * @param defaultValues 310 * The default values to return if the attribute is empty. 311 * @return The values decoded as a set of {@code Boolean}s. 312 */ 313 public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) { 314 return asSetOf(Functions.byteStringToBoolean(), defaultValues); 315 } 316 317 /** 318 * Returns the values contained in the attribute, or {@code defaultValues} 319 * if the attribute does not contain any values. 320 * 321 * @param defaultValues 322 * The default values to return if the attribute is empty. 323 * @return The values contained in the attribute. 324 */ 325 public Set<ByteString> asSetOfByteString(final ByteString... defaultValues) { 326 return asSetOfByteString(Arrays.asList(defaultValues)); 327 } 328 329 /** 330 * Returns the values contained in the attribute, or {@code defaultValues} 331 * if the attribute does not contain any values. 332 * 333 * @param defaultValues 334 * The default values to return if the attribute is empty. 335 * @return The values contained in the attribute. 336 */ 337 public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) { 338 return asSetOf(Functions.<ByteString> identityFunction(), defaultValues); 339 } 340 341 /** 342 * Returns the values decoded as a set of {@code GeneralizedTime}s using the 343 * generalized time syntax, or {@code defaultValues} if the attribute does 344 * not contain any values. 345 * 346 * @param defaultValues 347 * The default values to return if the attribute is empty. 348 * @return The values decoded as a set of {@code GeneralizedTime}s. 349 */ 350 public Set<GeneralizedTime> asSetOfGeneralizedTime( 351 final Collection<GeneralizedTime> defaultValues) { 352 return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues); 353 } 354 355 /** 356 * Returns the values decoded as a set of {@code GeneralizedTime}s using the 357 * generalized time syntax, or {@code defaultValues} if the attribute does 358 * not contain any values. 359 * 360 * @param defaultValues 361 * The default values to return if the attribute is empty. 362 * @return The values decoded as a set of {@code GeneralizedTime}s. 363 */ 364 public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) { 365 return asSetOfGeneralizedTime(Arrays.asList(defaultValues)); 366 } 367 368 /** 369 * Returns the values decoded as a set of {@code Integer}s, or 370 * {@code defaultValues} if the attribute does not contain any values. 371 * 372 * @param defaultValues 373 * The default values to return if the attribute is empty. 374 * @return The values decoded as a set of {@code Integer}s. 375 */ 376 public Set<Integer> asSetOfInteger(final Collection<Integer> defaultValues) { 377 return asSetOf(Functions.byteStringToInteger(), defaultValues); 378 } 379 380 /** 381 * Returns the values decoded as a set of {@code Integer}s, or 382 * {@code defaultValues} if the attribute does not contain any values. 383 * 384 * @param defaultValues 385 * The default values to return if the attribute is empty. 386 * @return The values decoded as a set of {@code Integer}s. 387 */ 388 public Set<Integer> asSetOfInteger(final Integer... defaultValues) { 389 return asSetOfInteger(Arrays.asList(defaultValues)); 390 } 391 392 /** 393 * Returns the values decoded as a set of {@code Long}s, or 394 * {@code defaultValues} if the attribute does not contain any values. 395 * 396 * @param defaultValues 397 * The default values to return if the attribute is empty. 398 * @return The values decoded as a set of {@code Long}s. 399 */ 400 public Set<Long> asSetOfLong(final Collection<Long> defaultValues) { 401 return asSetOf(Functions.byteStringToLong(), defaultValues); 402 } 403 404 /** 405 * Returns the values decoded as a set of {@code Long}s, or 406 * {@code defaultValues} if the attribute does not contain any values. 407 * 408 * @param defaultValues 409 * The default values to return if the attribute is empty. 410 * @return The values decoded as a set of {@code Long}s. 411 */ 412 public Set<Long> asSetOfLong(final Long... defaultValues) { 413 return asSetOfLong(Arrays.asList(defaultValues)); 414 } 415 416 /** 417 * Returns the values decoded as a set of {@code String}s, or 418 * {@code defaultValues} if the attribute does not contain any values. 419 * 420 * @param defaultValues 421 * The default values to return if the attribute is empty. 422 * @return The values decoded as a set of {@code String}s. 423 */ 424 public Set<String> asSetOfString(final Collection<String> defaultValues) { 425 return asSetOf(Functions.byteStringToString(), defaultValues); 426 } 427 428 /** 429 * Returns the values decoded as a set of {@code String}s, or 430 * {@code defaultValues} if the attribute does not contain any values. 431 * 432 * @param defaultValues 433 * The default values to return if the attribute is empty. 434 * @return The values decoded as a set of {@code String}s. 435 */ 436 public Set<String> asSetOfString(final String... defaultValues) { 437 return asSetOfString(Arrays.asList(defaultValues)); 438 } 439 440 /** 441 * Returns the first value decoded as a {@code String}, or {@code null} if 442 * the attribute does not contain any values. 443 * 444 * @return The first value decoded as a {@code String}. 445 */ 446 public String asString() { 447 return asString(null); 448 } 449 450 /** 451 * Returns the first value decoded as a {@code String}, or 452 * {@code defaultValue} if the attribute does not contain any values. 453 * 454 * @param defaultValue 455 * The default value to return if the attribute is empty. 456 * @return The first value decoded as a {@code String}. 457 */ 458 public String asString(final String defaultValue) { 459 return as(Functions.byteStringToString(), defaultValue); 460 } 461 462 /** 463 * Throws a {@code NoSuchElementException} if the attribute referenced by 464 * this parser is {@code null} or empty. 465 * 466 * @return A reference to this attribute parser. 467 * @throws NoSuchElementException 468 * If the attribute referenced by this parser is {@code null} or 469 * empty. 470 */ 471 public AttributeParser requireValue() throws NoSuchElementException { 472 if (isEmpty(attribute)) { 473 throw new NoSuchElementException(); 474 } else { 475 return this; 476 } 477 } 478 479 /** 480 * Sets the {@code Schema} which will be used when parsing schema sensitive 481 * values such as DNs and attribute descriptions. 482 * 483 * @param schema 484 * The {@code Schema} which will be used when parsing schema 485 * sensitive values. 486 * @return This attribute parser. 487 */ 488 public AttributeParser usingSchema(final Schema schema) { 489 // Avoid modifying the null instance: a schema will not be needed 490 // anyway. 491 if (this != NULL_INSTANCE) { 492 this.schema = schema; 493 } 494 return this; 495 } 496 497 private Schema getSchema() { 498 return schema == null ? Schema.getDefaultSchema() : schema; 499 } 500}