/* * ==================== * 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]" * ==================== */ package org.identityconnectors.framework.common.objects; import static org.identityconnectors.framework.common.objects.NameUtil.nameHashCode; import static org.identityconnectors.framework.common.objects.NameUtil.namesEqual; import java.util.Collections; import java.util.EnumSet; import java.util.Set; import org.identityconnectors.common.Assertions; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.common.StringUtil; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.api.operations.GetApiOp; import org.identityconnectors.framework.api.operations.SearchApiOp; import org.identityconnectors.framework.api.operations.SyncApiOp; import org.identityconnectors.framework.common.FrameworkUtil; import org.identityconnectors.framework.common.serializer.SerializerUtil; /** * <i>AttributeInfo</i> is meta data responsible for describing an * {@link Attribute}. It can be programmatically determined at runtime or * statically constructed. The class determines if an {@link Attribute} is * required, readable, writable, or nullable. In also includes the native type * and name. It is recommended that date fields be represented as a long with * time zone UTC. It should be up to the display or separate attributes if the * time zone is necessary. */ public final class AttributeInfo { private final String name; private final Class<?> type; private final Set<Flags> flags; /** * Enum of modifier flags to use for attributes. Note that this enum is * designed for configuration by exception such that an empty set of flags * are the defaults: * <ul> * <li>updateable</li> * <li>creatable</li> * <li>returned by default</li> * <li>readable</li> * <li>single-valued</li> * <li>optional</li> * </ul> */ public static enum Flags { REQUIRED, MULTIVALUED, NOT_CREATABLE, NOT_UPDATEABLE, NOT_READABLE, NOT_RETURNED_BY_DEFAULT } AttributeInfo(final String name, final Class<?> type, final Set<Flags> flags) { if (StringUtil.isBlank(name)) { throw new IllegalStateException("Name must not be blank!"); } if ((OperationalAttributes.PASSWORD_NAME.equals(name) || OperationalAttributes.CURRENT_PASSWORD_NAME .equals(name)) && !GuardedString.class.equals(type)) { throw new IllegalArgumentException( "Password based attributes must be of type GuardedString."); } Assertions.nullCheck(flags, "flags"); // check the type.. FrameworkUtil.checkAttributeType(type); this.name = name; this.type = type; this.flags = Collections.unmodifiableSet(EnumSet.copyOf(flags)); if (!isReadable() && isReturnedByDefault()) { throw new IllegalArgumentException( "Attribute " + name + " is flagged as not-readable, so it should also be as not-returned-by-default."); } } /** * The native name of the attribute. * * @return the native name of the attribute its describing. */ public String getName() { return name; } /** * The basic type associated with this attribute. All primitives are * supported. * * @return the native type if uses. */ public Class<?> getType() { return type; } /** * Returns the set of flags associated with the attribute. * * @return the set of flags associated with the attribute */ public Set<Flags> getFlags() { return flags; } /** * Determines if the attribute is readable. * * @return true if the attribute is readable else false. */ public boolean isReadable() { return !flags.contains(Flags.NOT_READABLE); } /** * Determines if the attribute is writable on create. * * @return true if the attribute is writable on create else false. */ public boolean isCreateable() { return !flags.contains(Flags.NOT_CREATABLE); } /** * Determines if the attribute is writable on update. * * @return true if the attribute is writable on update else false. */ public boolean isUpdateable() { return !flags.contains(Flags.NOT_UPDATEABLE); } /** * Determines whether this attribute is required for creates. * * @return true if the attribute is required for an object else false. */ public boolean isRequired() { return flags.contains(Flags.REQUIRED); } /** * Determines if this attribute can handle multiple values. * * There is a special case with byte[] since in most instances this denotes * a single object. * * @return true if the attribute is multi-value otherwise false. */ public boolean isMultiValued() { return flags.contains(Flags.MULTIVALUED); } /** * Determines if the attribute is returned by default. * * Indicates if an {@link Attribute} will be returned during * {@link SearchApiOp}, {@link SyncApiOp} or {@link GetApiOp} inside a * {@link ConnectorObject} by default. The default value is * <code>true</code>. * * @return false if the attribute should not be returned by default. */ public boolean isReturnedByDefault() { return !flags.contains(Flags.NOT_RETURNED_BY_DEFAULT); } /** * Determines if the name parameter matches this {@link AttributeInfo}. */ public boolean is(String name) { return namesEqual(this.name, name); } // ======================================================================= // Object Overrides // ======================================================================= @Override public boolean equals(Object obj) { boolean ret = false; if (obj instanceof AttributeInfo) { AttributeInfo other = (AttributeInfo) obj; if (!is(other.getName())) { return false; } if (!getType().equals(other.getType())) { return false; } if (!CollectionUtil.equals(flags, other.flags)) { return false; } return true; } return ret; } @Override public int hashCode() { return nameHashCode(name); } @Override public String toString() { return SerializerUtil.serializeXmlObject(this, false); } }