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