/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://opensource.org/licenses/cddl1.php * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at http://opensource.org/licenses/cddl1.php. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2014 ForgeRock AS. */ package org.identityconnectors.framework.common.objects; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.identityconnectors.common.Assertions; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.common.security.GuardedByteArray; import org.identityconnectors.common.security.GuardedString; /** * Utility methods to retrieve values from instances of {@link Attribute}. */ public final class AttributeUtil { /** * Never allow this to be instantiated. */ private AttributeUtil() { } /** * Get the string value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the string value. * @return null if the value is null otherwise the string value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a string. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static String getStringValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (String) obj; } /** * Get the character value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the character value. * @return null if the value is null otherwise the character value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a character. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static Character getCharacterValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Character) obj; } /** * Get the {@link GuardedByteArray} value from the specified (single-valued) * attribute. * * @param attr * Attribute from which to retrieve the guarded byte array value. * @return null if the value is null otherwise the guarded byte array value * for the attribute. * @throws ClassCastException * if the object in the attribute is not a GuardedByteArray. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static GuardedByteArray getGuardedByteArrayValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (GuardedByteArray) obj; } /** * Get the {@link GuardedString} value from the specified (single-valued) * attribute. * * @param attr * Attribute from which to retrieve the guarded string value. * @return null if the value is null otherwise the guarded string value for * the attribute. * @throws ClassCastException * if the object in the attribute is not a GuardedString. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static GuardedString getGuardedStringValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (GuardedString) obj; } /** * Get the string value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the string value. * @return null if the value is null otherwise the string value for the * attribute. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static String getAsStringValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : obj.toString(); } /** * Get the byte value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the byte value. * @return null if the value is null otherwise the byte value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a byte. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static Byte getByteValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Byte) obj; } /** * Get the byte array value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the byte array value. * @return null if the value is null otherwise the byte array value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a byte array. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static Byte[] getByteArrayValue(final Attribute attr) { final Object obj = getSingleValue(attr); if (obj instanceof byte[]) { Byte[] copy = new Byte[((byte[]) obj).length]; for (int idx = 0; idx < ((byte[]) obj).length; ++idx) { copy[idx] = ((byte[]) obj)[idx]; } return copy; } else { return obj == null ? null : (Byte[]) obj; } } /** * Get the integer value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the integer value. * @return null if the value is null otherwise the integer value for the * attribute. * @throws ClassCastException * if the object in the attribute is not an integer. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static Integer getIntegerValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Integer) obj; } /** * Get the long value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the long value. * @return null if the value is null otherwise the long value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a long. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static Long getLongValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Long) obj; } /** * Get the float value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the float value. * @return null if the value is null otherwise the float value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a float. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static Float getFloatValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Float) obj; } /** * Get the date value from the specified (single-valued) attribute that * contains a long. * * @param attr * Attribute from which to retrieve the date value. * @return null if the value is null otherwise the date value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a long. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static Date getDateValue(final Attribute attr) { final Long value = getLongValue(attr); return value == null ? null : new Date(value.longValue()); } /** * Get the double value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the double value. * @return null if the value is null otherwise the double value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a double. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued).. */ public static Double getDoubleValue(final Attribute attr) { Object obj = getSingleValue(attr); return obj != null ? (Double) obj : null; } /** * Get the big decimal value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the big decimal value. * @return null if the value is null otherwise the big decimal value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a big decimal. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static BigDecimal getBigDecimalValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (BigDecimal) obj; } /** * Get the big integer value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the big integer value. * @return null if the value is null otherwise the big integer value for the * attribute. * @throws ClassCastException * if the object in the attribute is not a big integer. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). * @since 1.4 */ public static BigInteger getBigIntegerValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (BigInteger) obj; } /** * Get the boolean value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the boolean value. * @return null if the value is null otherwise the boolean value for the * attribute. * @throws ClassCastException * if the object in the attribute is not an {@link Boolean}. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ public static Boolean getBooleanValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Boolean) obj; } /** * Get the map value from the specified (single-valued) attribute. * * @param attr * Attribute from which to retrieve the map value. * @return null if the value is null otherwise the map value for the * attribute. * @throws ClassCastException * if the object in the attribute is not an {@link Map}. * @throws IllegalArgumentException * if the attribute is a multi-valued (rather than * single-valued). */ @SuppressWarnings("unchecked") public static Map<String, Object> getMapValue(final Attribute attr) { final Object obj = getSingleValue(attr); return obj == null ? null : (Map<String, Object>) obj; } /** * Get the <code>Object</code> value from the specified (single-valued) * attribute. * * @return <code>null</code> if the attribute's list of values is * <code>null</code> or empty. */ public static Object getSingleValue(final Attribute attr) { Object ret = null; final List<Object> val = attr.getValue(); if (val != null && !val.isEmpty()) { // make sure this only called for single value.. if (val.size() > 1) { final StringBuilder msg = new StringBuilder("The ").append(attr.getName()).append( " attribute is not single value attribute."); throw new IllegalArgumentException(msg.toString()); } ret = val.get(0); } return ret; } /** * Transform a <code>Collection</code> of {@link Attribute} instances into a * {@link Map}. * * The key to each element in the map is the <i>name</i> of an * <code>Attribute</code>. The value of each element in the map is the * <code>Attribute</code> instance with that name. * * @param attributes * set of attribute to transform to a map. * @return a map of string and attribute. * @throws NullPointerException * if the parameter <strong>attributes</strong> is * <strong>null</strong>. */ public static Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) { final Map<String, Attribute> ret = CollectionUtil.<Attribute> newCaseInsensitiveMap(); for (Attribute attr : attributes) { ret.put(attr.getName(), attr); } return CollectionUtil.asReadOnlyMap(ret); } /** * Get the {@link Uid} from the specified set of attributes. * * @param attrs * set of {@link Attribute}s that may contain a {@link Uid}. * @return null if the set does not contain a {@link Uid} object the first * one found. */ public static Uid getUidAttribute(final Set<Attribute> attrs) { return (Uid) find(Uid.NAME, attrs); } /** * Filter out any special attribute from the specified set. * * Special attributes include {@link Name}, {@link Uid}, and * {@link OperationalAttributes}. * * @param attrs * set of {@link Attribute}s to filter out the operational and * default attributes. * @return a set that only contains plain attributes or empty. */ public static Set<Attribute> getBasicAttributes(final Set<Attribute> attrs) { final Set<Attribute> ret = new HashSet<Attribute>(); for (Attribute attr : attrs) { // note this is dangerous because we need to be consistent // in the naming of special attributes. if (!isSpecial(attr)) { ret.add(attr); } } return ret; } /** * Filter out any basic attributes from the specified set, leaving only * special attributes. * * Special attributes include {@link Name}, {@link Uid}, and * {@link OperationalAttributes}. * * @param attrs * set of {@link Attribute}s to filter out the basic attributes * @return a set that only contains special attributes or an empty set if * there are none. */ public static Set<Attribute> getSpecialAttributes(final Set<Attribute> attrs) { final Set<Attribute> ret = new HashSet<Attribute>(); for (Attribute attr : attrs) { if (isSpecial(attr)) { ret.add(attr); } } return ret; } /** * Returns a mutable copy of the original set with the uid attribute * removed. * * @param attrs * The original set. Must not be null. * @return A mutable copy of the original set with the uid attribute * removed. */ public static Set<Attribute> filterUid(final Set<Attribute> attrs) { Assertions.nullCheck(attrs, "attrs"); final Set<Attribute> ret = new HashSet<Attribute>(); for (Attribute attr : attrs) { if (!(attr instanceof Uid)) { ret.add(attr); } } return ret; } /** * Returns a mutable copy of the original set with the uid attribute added. * * @param attrs * The original set. Must not be null. * @param uid * The uid. Must not be null. * @return A mutable copy of the original set with the uid attribute added. */ public static Set<Attribute> addUid(final Set<Attribute> attrs, final Uid uid) { Assertions.nullCheck(attrs, "attrs"); Assertions.nullCheck(uid, "uid"); final Set<Attribute> ret = new HashSet<Attribute>(attrs); ret.add(uid); return ret; } /** * Determines whether the specified attribute is a special attribute. * Special attributes include {@link Uid}, {@link ObjectClass} and * {@link OperationalAttributes}. * * @param attr * {@link Attribute} to test for against. * @return true if the attribute value is a {@link Uid}, {@link ObjectClass} * or one of the {@link OperationalAttributes}. * @throws NullPointerException * if the attribute parameter is null. */ public static boolean isSpecial(final Attribute attr) { return isSpecialName(attr.getName()); } /** * Determines whether the specified attribute info is for a special * attribute. Special attributes include {@link Uid}, {@link ObjectClass} * and {@link OperationalAttributes}. * * @param attr * {@link AttributeInfo} to test for against. * @return true if the attribute value is a {@link Uid}, {@link ObjectClass} * or one of the {@link OperationalAttributes}. * @throws NullPointerException * if the attribute parameter is null. */ public static boolean isSpecial(final AttributeInfo attr) { final String name = attr.getName(); return isSpecialName(name); } /** * Determines whether the specified attribute name is special in the sense * of {@link #createSpecialName}. * * @param name * the attribute name to test against. * @return true if the attribute name is special. */ public static boolean isSpecialName(final String name) { return NameUtil.isSpecialName(name); } /** * Create a special name from the specified name. Add the <code>__</code> * string as both prefix and suffix. This indicates that an attribute name * identifies a "special attribute" such as {@link Uid}, {@link ObjectClass} * or one of the {@link OperationalAttributes}. */ public static String createSpecialName(final String name) { return NameUtil.createSpecialName(name); } /** * Compares two attribute names for equality. * * @param name1 * the first attribute name. * @param name2 * the second attribute name. * @return true if the two attribute names are equal. */ public static boolean namesEqual(final String name1, final String name2) { return NameUtil.namesEqual(name1, name2); } /** * Get the {@link Name} attribute from the specified set of attributes. * * @param attrs * set of attributes to search against. * @return the {@link Name} attribute it if exsist otherwise * <code>null</code>. */ public static Name getNameFromAttributes(final Set<Attribute> attrs) { return (Name) find(Name.NAME, attrs); } /** * Find the {@link Attribute} of the given name in the {@link Set}. * * @param name * {@link Attribute}'s name to search for. * @param attrs * {@link Set} of attribute to search. * @return {@link Attribute} with the specified otherwise <code>null</code>. */ public static Attribute find(final String name, final Set<Attribute> attrs) { Assertions.nullCheck(name, "name"); final Set<Attribute> set = CollectionUtil.nullAsEmpty(attrs); for (Attribute attr : set) { if (attr.is(name)) { return attr; } } return null; } /** * Get the password value from the provided set of {@link Attribute}s. */ public static GuardedString getPasswordValue(final Set<Attribute> attrs) { final Attribute pwd = find(OperationalAttributes.PASSWORD_NAME, attrs); return (pwd == null) ? null : getGuardedStringValue(pwd); } /** * Get the current password value from the provided set of {@link Attribute} * s. * * @param attrs * Set of {@link Attribute}s that may contain the current * password {@link OperationalAttributes#CURRENT_PASSWORD_NAME} * {@link Attribute}. * @return <code>null</code> if it does not exist in the {@link Set} else * the value. */ public static GuardedString getCurrentPasswordValue(final Set<Attribute> attrs) { final Attribute pwd = find(OperationalAttributes.CURRENT_PASSWORD_NAME, attrs); return (pwd == null) ? null : getGuardedStringValue(pwd); } /** * Determine if the {@link ConnectorObject} is locked out. By getting the * value of the {@link OperationalAttributes#LOCK_OUT_NAME}. * * @param obj * {@link ConnectorObject} object to inspect. * @throws NullPointerException * if the parameter 'obj' is <code>null</code>. * @return <code>null</code> if the attribute does not exist otherwise to * value of the {@link Attribute}. */ public static Boolean isLockedOut(final ConnectorObject obj) { final Attribute attr = obj.getAttributeByName(OperationalAttributes.LOCK_OUT_NAME); return (attr == null) ? null : getBooleanValue(attr); } /** * Determine if the {@link ConnectorObject} is enable. By getting the value * of the {@link OperationalAttributes#ENABLE_NAME}. * * @param obj * {@link ConnectorObject} object to inspect. * @throws IllegalStateException * if the object does not contain attribute in question. * @throws NullPointerException * if the parameter 'obj' is <code>null</code>. * @return <code>null</code> if the attribute does not exist otherwise to * value of the {@link Attribute}. */ public static Boolean isEnabled(final ConnectorObject obj) { final Attribute attr = obj.getAttributeByName(OperationalAttributes.ENABLE_NAME); return (attr == null) ? null : getBooleanValue(attr); } /** * Retrieve the password expiration date from the {@link ConnectorObject}. * * @param obj * {@link ConnectorObject} object to inspect. * @throws IllegalStateException * if the object does not contain attribute in question. * @throws NullPointerException * if the parameter 'obj' is <code>null</code>. * @return <code>null</code> if the {@link Attribute} does not exist * otherwise the value of the {@link Attribute}. */ public static Date getPasswordExpirationDate(final ConnectorObject obj) { final Attribute attr = obj.getAttributeByName(OperationalAttributes.PASSWORD_EXPIRATION_DATE_NAME); return (attr == null) ? null : new Date(getLongValue(attr)); } /** * Get the password expired attribute from a {@link Collection} of * {@link Attribute}s. * * @param attrs * set of attribute to find the expired password * {@link Attribute}. * @return <code>null</code> if the attribute does not exist and the value * of the {@link Attribute} if it does. */ public static Boolean getPasswordExpired(final Set<Attribute> attrs) { final Attribute pwd = find(OperationalAttributes.PASSWORD_EXPIRED_NAME, attrs); return (pwd == null) ? null : getBooleanValue(pwd); } /** * Determine if the password is expired for this object. * * @param obj * {@link ConnectorObject} that should contain a password expired * attribute. * @return <code>null</code> if the attribute does not exist and the value * of the {@link Attribute} if it does. */ public static Boolean isPasswordExpired(final ConnectorObject obj) { final Attribute pwd = obj.getAttributeByName(OperationalAttributes.PASSWORD_EXPIRED_NAME); return (pwd == null) ? null : getBooleanValue(pwd); } /** * Get the enable date from the set of attributes. * * @param attrs * set of attribute to find the enable date {@link Attribute}. * @return <code>null</code> if the attribute does not exist and the value * of the {@link Attribute} if it does. */ public static Date getEnableDate(final Set<Attribute> attrs) { final Attribute date = find(OperationalAttributes.ENABLE_DATE_NAME, attrs); return (date == null) ? null : getDateValue(date); } }