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 2009-2010 Sun Microsystems, Inc. 015 * Portions copyright 2012-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.ldap; 018 019import org.forgerock.i18n.LocalizableMessage; 020import org.forgerock.i18n.LocalizedIllegalArgumentException; 021import org.forgerock.opendj.ldap.schema.Schema; 022import org.forgerock.util.Function; 023import org.forgerock.util.promise.NeverThrowsException; 024 025import com.forgerock.opendj.util.StaticUtils; 026 027import static org.forgerock.opendj.ldap.schema.Schema.*; 028 029import static com.forgerock.opendj.ldap.CoreMessages.*; 030 031import java.security.cert.CertificateException; 032import java.security.cert.CertificateFactory; 033import java.security.cert.X509Certificate; 034 035/** 036 * Common {@link Function} implementations which may be used when parsing 037 * attributes. 038 * 039 * @see Entry#parseAttribute 040 * @see Attribute#parse 041 * @see AttributeParser 042 */ 043public final class Functions { 044 045 private static final Function<ByteString, String, NeverThrowsException> BYTESTRING_TO_STRING = 046 new Function<ByteString, String, NeverThrowsException>() { 047 @Override 048 public String apply(final ByteString value) { 049 return value.toString(); 050 } 051 }; 052 053 private static final Function<Object, Object, NeverThrowsException> IDENTITY = 054 new Function<Object, Object, NeverThrowsException>() { 055 @Override 056 public Object apply(final Object value) { 057 return value; 058 } 059 }; 060 061 private static final Function<String, String, NeverThrowsException> NORMALIZE_STRING = 062 new Function<String, String, NeverThrowsException>() { 063 @Override 064 public String apply(final String value) { 065 return StaticUtils.toLowerCase(value).trim(); 066 } 067 }; 068 069 private static final Function<Object, ByteString, NeverThrowsException> OBJECT_TO_BYTESTRING = 070 new Function<Object, ByteString, NeverThrowsException>() { 071 @Override 072 public ByteString apply(final Object value) { 073 return ByteString.valueOfObject(value); 074 } 075 }; 076 077 private static final Function<String, Boolean, LocalizedIllegalArgumentException> STRING_TO_BOOLEAN = 078 new Function<String, Boolean, LocalizedIllegalArgumentException>() { 079 @Override 080 public Boolean apply(final String value) { 081 final String valueString = StaticUtils.toLowerCase(value); 082 if ("true".equals(valueString) || "yes".equals(valueString) 083 || "on".equals(valueString) || "1".equals(valueString)) { 084 return Boolean.TRUE; 085 } else if ("false".equals(valueString) || "no".equals(valueString) 086 || "off".equals(valueString) || "0".equals(valueString)) { 087 return Boolean.FALSE; 088 } else { 089 throw new LocalizedIllegalArgumentException( 090 WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(valueString)); 091 } 092 } 093 }; 094 095 private static final Function<String, GeneralizedTime, LocalizedIllegalArgumentException> STRING_TO_GTIME = 096 new Function<String, GeneralizedTime, LocalizedIllegalArgumentException>() { 097 @Override 098 public GeneralizedTime apply(final String value) { 099 return GeneralizedTime.valueOf(value); 100 } 101 }; 102 103 private static final Function<String, Integer, LocalizedIllegalArgumentException> STRING_TO_INTEGER = 104 new Function<String, Integer, LocalizedIllegalArgumentException>() { 105 @Override 106 public Integer apply(final String value) { 107 try { 108 return Integer.valueOf(value); 109 } catch (final NumberFormatException e) { 110 final LocalizableMessage message = FUNCTIONS_TO_INTEGER_FAIL.get(value); 111 throw new LocalizedIllegalArgumentException(message); 112 } 113 } 114 }; 115 116 private static final Function<String, Long, LocalizedIllegalArgumentException> STRING_TO_LONG = 117 new Function<String, Long, LocalizedIllegalArgumentException>() { 118 @Override 119 public Long apply(final String value) { 120 try { 121 return Long.valueOf(value); 122 } catch (final NumberFormatException e) { 123 final LocalizableMessage message = FUNCTIONS_TO_LONG_FAIL.get(value); 124 throw new LocalizedIllegalArgumentException(message); 125 } 126 } 127 }; 128 129 private static final Function<ByteString, Boolean, LocalizedIllegalArgumentException> BYTESTRING_TO_BOOLEAN = 130 compose(byteStringToString(), STRING_TO_BOOLEAN); 131 132 private static final Function<ByteString, X509Certificate, LocalizedIllegalArgumentException> BYTESTRING_TO_CERT = 133 new Function<ByteString, X509Certificate, LocalizedIllegalArgumentException>() { 134 @Override 135 public X509Certificate apply(final ByteString value) { 136 try { 137 final CertificateFactory factory = CertificateFactory.getInstance("X.509"); 138 return (X509Certificate) factory.generateCertificate(value.asReader().asInputStream()); 139 } catch (CertificateException e) { 140 final String head = value.subSequence(0, Math.min(value.length(), 8)).toHexString(); 141 throw new LocalizedIllegalArgumentException(FUNCTIONS_TO_CERT_FAIL.get(head), e); 142 } 143 } 144 }; 145 146 private static final Function<ByteString, GeneralizedTime, LocalizedIllegalArgumentException> BYTESTRING_TO_GTIME = 147 compose(byteStringToString(), STRING_TO_GTIME); 148 149 private static final Function<ByteString, Integer, LocalizedIllegalArgumentException> BYTESTRING_TO_INTEGER = 150 compose(byteStringToString(), STRING_TO_INTEGER); 151 152 private static final Function<ByteString, Long, LocalizedIllegalArgumentException> BYTESTRING_TO_LONG = 153 compose(byteStringToString(), STRING_TO_LONG); 154 155 /** 156 * Creates a function that returns constant value for any input. 157 * 158 * @param <M> 159 * The type of input values transformed by this function. 160 * @param <N> 161 * The type of output values returned by this function. 162 * @param constant 163 * The constant value for the function to return 164 * @return A function that always returns constant value. 165 */ 166 public static <M, N> Function<M, N, NeverThrowsException> returns(final N constant) { 167 return new Function<M, N, NeverThrowsException>() { 168 @Override 169 public N apply(M value) { 170 return constant; 171 } 172 }; 173 } 174 175 /** 176 * Returns the composition of two functions. The result of the first 177 * function will be passed to the second. 178 * 179 * @param <M> 180 * The type of input values transformed by this function. 181 * @param <N> 182 * The type of output values returned by this function. 183 * @param <X> 184 * The type of intermediate values passed between the two 185 * functions. 186 * @param <E> 187 * The type of exception thrown by the {@code second} function. 188 * @param first 189 * The first function which will consume the input. 190 * @param second 191 * The second function which will produce the result. 192 * @return The composition. 193 */ 194 public static <M, X, N, E extends Exception> Function<M, N, E> compose( 195 final Function<M, X, NeverThrowsException> first, final Function<X, N, E> second) { 196 return new Function<M, N, E>() { 197 @Override 198 public N apply(final M value) throws E { 199 return second.apply(first.apply(value)); 200 } 201 }; 202 } 203 204 /** 205 * Returns a function which always returns the value that it was provided 206 * with. 207 * 208 * @param <M> 209 * The type of values transformed by this function. 210 * @return A function which always returns the value that it was provided 211 * with. 212 */ 213 @SuppressWarnings("unchecked") 214 public static <M> Function<M, M, NeverThrowsException> identityFunction() { 215 return (Function<M, M, NeverThrowsException>) IDENTITY; 216 } 217 218 /** 219 * Returns a function which converts a {@code String} to lower case using 220 * {@link StaticUtils#toLowerCase} and then trims it. 221 * 222 * @return A function which converts a {@code String} to lower case using 223 * {@link StaticUtils#toLowerCase} and then trims it. 224 */ 225 public static Function<String, String, NeverThrowsException> normalizeString() { 226 return NORMALIZE_STRING; 227 } 228 229 /** 230 * Returns a function which converts an {@code Object} to a 231 * {@code ByteString} using the {@link ByteString#valueOfObject(Object)} method. 232 * 233 * @return A function which converts an {@code Object} to a 234 * {@code ByteString} . 235 */ 236 public static Function<Object, ByteString, NeverThrowsException> objectToByteString() { 237 return OBJECT_TO_BYTESTRING; 238 } 239 240 /** 241 * Returns a function which parses {@code AttributeDescription}s using the 242 * default schema. Invalid values will result in a 243 * {@code LocalizedIllegalArgumentException}. 244 * 245 * @return A function which parses {@code AttributeDescription}s. 246 */ 247 public static Function<String, AttributeDescription, LocalizedIllegalArgumentException> 248 stringToAttributeDescription() { 249 return stringToAttributeDescription(getDefaultSchema()); 250 } 251 252 /** 253 * Returns a function which parses {@code AttributeDescription}s using the 254 * provided schema. Invalid values will result in a 255 * {@code LocalizedIllegalArgumentException}. 256 * 257 * @param schema 258 * The schema to use for decoding attribute descriptions. 259 * @return A function which parses {@code AttributeDescription}s. 260 */ 261 public static Function<String, AttributeDescription, LocalizedIllegalArgumentException> 262 stringToAttributeDescription(final Schema schema) { 263 return new Function<String, AttributeDescription, LocalizedIllegalArgumentException>() { 264 @Override 265 public AttributeDescription apply(final String value) { 266 return AttributeDescription.valueOf(value, schema); 267 } 268 }; 269 } 270 271 /** 272 * Returns a function which parses {@code Boolean} values. The function will 273 * accept the values {@code 0}, {@code false}, {@code no}, {@code off}, 274 * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will 275 * result in a {@code LocalizedIllegalArgumentException}. 276 * 277 * @return A function which parses {@code Boolean} values. 278 */ 279 public static Function<String, Boolean, LocalizedIllegalArgumentException> stringToBoolean() { 280 return STRING_TO_BOOLEAN; 281 } 282 283 /** 284 * Returns a function which parses {@code DN}s using the default schema. 285 * Invalid values will result in a {@code LocalizedIllegalArgumentException} 286 * . 287 * 288 * @return A function which parses {@code DN}s. 289 */ 290 public static Function<String, DN, LocalizedIllegalArgumentException> stringToDN() { 291 return stringToDN(getDefaultSchema()); 292 } 293 294 /** 295 * Returns a function which parses {@code DN}s using the provided schema. 296 * Invalid values will result in a {@code LocalizedIllegalArgumentException} 297 * . 298 * 299 * @param schema 300 * The schema to use for decoding DNs. 301 * @return A function which parses {@code DN}s. 302 */ 303 public static Function<String, DN, LocalizedIllegalArgumentException> stringToDN(final Schema schema) { 304 return new Function<String, DN, LocalizedIllegalArgumentException>() { 305 @Override 306 public DN apply(final String value) { 307 return DN.valueOf(value, schema); 308 } 309 }; 310 } 311 312 /** 313 * Returns a function which parses generalized time strings. Invalid values 314 * will result in a {@code LocalizedIllegalArgumentException}. 315 * 316 * @return A function which parses generalized time strings. 317 */ 318 public static Function<String, GeneralizedTime, LocalizedIllegalArgumentException> stringToGeneralizedTime() { 319 return STRING_TO_GTIME; 320 } 321 322 /** 323 * Returns a function which parses {@code Integer} string values. Invalid 324 * values will result in a {@code LocalizedIllegalArgumentException}. 325 * 326 * @return A function which parses {@code Integer} string values. 327 */ 328 public static Function<String, Integer, LocalizedIllegalArgumentException> stringToInteger() { 329 return STRING_TO_INTEGER; 330 } 331 332 /** 333 * Returns a function which parses {@code Long} string values. Invalid 334 * values will result in a {@code LocalizedIllegalArgumentException}. 335 * 336 * @return A function which parses {@code Long} string values. 337 */ 338 public static Function<String, Long, LocalizedIllegalArgumentException> stringToLong() { 339 return STRING_TO_LONG; 340 } 341 342 /** 343 * Returns a function which parses {@code AttributeDescription}s using the 344 * default schema. Invalid values will result in a 345 * {@code LocalizedIllegalArgumentException}. 346 * 347 * @return A function which parses {@code AttributeDescription}s. 348 */ 349 public static Function<ByteString, AttributeDescription, LocalizedIllegalArgumentException> 350 byteStringToAttributeDescription() { 351 return byteStringToAttributeDescription(getDefaultSchema()); 352 } 353 354 /** 355 * Returns a function which parses {@code AttributeDescription}s using the 356 * provided schema. Invalid values will result in a 357 * {@code LocalizedIllegalArgumentException}. 358 * 359 * @param schema 360 * The schema to use for decoding attribute descriptions. 361 * @return A function which parses {@code AttributeDescription}s. 362 */ 363 public static Function<ByteString, AttributeDescription, LocalizedIllegalArgumentException> 364 byteStringToAttributeDescription(final Schema schema) { 365 return compose(byteStringToString(), stringToAttributeDescription(schema)); 366 } 367 368 /** 369 * Returns a function which parses {@code Boolean} values. The function will 370 * accept the values {@code 0}, {@code false}, {@code no}, {@code off}, 371 * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will 372 * result in a {@code LocalizedIllegalArgumentException}. 373 * 374 * @return A function which parses {@code Boolean} values. 375 */ 376 public static Function<ByteString, Boolean, LocalizedIllegalArgumentException> byteStringToBoolean() { 377 return BYTESTRING_TO_BOOLEAN; 378 } 379 380 /** 381 * Returns a function which parses {@code DN}s using the default schema. 382 * Invalid values will result in a {@code LocalizedIllegalArgumentException} 383 * . 384 * 385 * @return A function which parses {@code DN}s. 386 */ 387 public static Function<ByteString, DN, LocalizedIllegalArgumentException> byteStringToDN() { 388 return byteStringToDN(getDefaultSchema()); 389 } 390 391 /** 392 * Returns a function which parses {@code DN}s using the provided schema. 393 * Invalid values will result in a {@code LocalizedIllegalArgumentException} 394 * . 395 * 396 * @param schema 397 * The schema to use for decoding DNs. 398 * @return A function which parses {@code DN}s. 399 */ 400 public static Function<ByteString, DN, LocalizedIllegalArgumentException> byteStringToDN(final Schema schema) { 401 return compose(byteStringToString(), stringToDN(schema)); 402 } 403 404 /** 405 * Returns a function which parses {@code X509Certificate} values. Invalid values will 406 * result in a {@code LocalizedIllegalArgumentException}. 407 * 408 * @return A function which parses {@code X509Certificate} values. 409 */ 410 public static Function<ByteString, X509Certificate, LocalizedIllegalArgumentException> byteStringToCertificate() { 411 return BYTESTRING_TO_CERT; 412 } 413 414 /** 415 * Returns a function which parses generalized time strings. Invalid values 416 * will result in a {@code LocalizedIllegalArgumentException}. 417 * 418 * @return A function which parses generalized time strings. 419 */ 420 public static Function<ByteString, GeneralizedTime, LocalizedIllegalArgumentException> 421 byteStringToGeneralizedTime() { 422 return BYTESTRING_TO_GTIME; 423 } 424 425 /** 426 * Returns a function which parses {@code Integer} string values. Invalid 427 * values will result in a {@code LocalizedIllegalArgumentException}. 428 * 429 * @return A function which parses {@code Integer} string values. 430 */ 431 public static Function<ByteString, Integer, LocalizedIllegalArgumentException> byteStringToInteger() { 432 return BYTESTRING_TO_INTEGER; 433 } 434 435 /** 436 * Returns a function which parses {@code Long} string values. Invalid 437 * values will result in a {@code LocalizedIllegalArgumentException}. 438 * 439 * @return A function which parses {@code Long} string values. 440 */ 441 public static Function<ByteString, Long, LocalizedIllegalArgumentException> byteStringToLong() { 442 return BYTESTRING_TO_LONG; 443 } 444 445 /** 446 * Returns a function which parses a {@code ByteString} as a UTF-8 encoded 447 * {@code String}. 448 * 449 * @return A function which parses the string representation of a 450 * {@code ByteString} as a UTF-8 encoded {@code String}. 451 */ 452 public static Function<ByteString, String, NeverThrowsException> byteStringToString() { 453 return BYTESTRING_TO_STRING; 454 } 455 456 /** Prevent instantiation. */ 457 private Functions() { 458 // Do nothing. 459 } 460 461}