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