/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2011-2013 ForgeRock AS */ package org.opends.server.types; import java.util.Collection; import java.util.List; import java.util.Map; import org.opends.server.api.ApproximateMatchingRule; import org.opends.server.api.AttributeSyntax; import org.opends.server.api.EqualityMatchingRule; import org.opends.server.api.OrderingMatchingRule; import org.opends.server.api.SubstringMatchingRule; import org.opends.server.core.DirectoryServer; import org.opends.server.schema.AttributeTypeSyntax; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.Validator.*; /** * This class defines a data structure for storing and interacting * with an attribute type, which contains information about the format * of an attribute and the syntax and matching rules that should be * used when interacting with it. * <p> * Any methods which accesses the set of names associated with this * attribute type, will retrieve the primary name as the first name, * regardless of whether or not it was contained in the original set * of <code>names</code> passed to the constructor. * <p> * Where ordered sets of names, or extra properties are provided, the * ordering will be preserved when the associated fields are accessed * via their getters or via the {@link #toString()} methods. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, mayInstantiate=false, mayExtend=false, mayInvoke=true) public final class AttributeType extends CommonSchemaElements implements SchemaFileElement, Comparable<AttributeType> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // The approximate matching rule for this attribute type. private final ApproximateMatchingRule approximateMatchingRule; // The syntax for this attribute type. private final AttributeSyntax<?> syntax; // The superior attribute type from which this attribute type // inherits. private final AttributeType superiorType; // The attribute usage for this attribute type. private final AttributeUsage attributeUsage; // Indicates whether this attribute type is declared "collective". private final boolean isCollective; // Indicates whether this attribute type is declared // "no-user-modification". private final boolean isNoUserModification; // Indicates whether this attribute type is the objectclass type. private final boolean isObjectClassType; // Indicates whether this attribute type is operational. private final boolean isOperational; // Indicates whether this attribute type is declared "single-value". private final boolean isSingleValue; // Indicates whether there is a possibility that this attribute type // may have one or more subtypes that list this type or one of its // subtypes as a superior. Note that this variable is intentional // not declared "final", but if it ever gets set to "true", then it // should never be unset back to "false". private boolean mayHaveSubordinateTypes; // The equality matching rule for this attribute type. private final EqualityMatchingRule equalityMatchingRule; // The ordering matching rule for this attribute type. private final OrderingMatchingRule orderingMatchingRule; // The definition string used to create this attribute type. private final String definition; // The OID for the associated syntax. private final String syntaxOID; // The substring matching rule for this attribute type. private final SubstringMatchingRule substringMatchingRule; // True once this attribute type has been removed from the schema. private volatile boolean isDirty = false; /** * Creates a new attribute type with the provided information. * <p> * If no <code>primaryName</code> is specified, but a set of * <code>names</code> is specified, then the first name retrieved * from the set of <code>names</code> will be used as the primary * name. * * @param definition * The definition string used to create this attribute * type. It must not be {@code null}. * @param primaryName * The primary name for this attribute type, or * <code>null</code> if there is no primary name. * @param typeNames * The full set of names for this attribute type, or * <code>null</code> if there are no names. * @param oid * The OID for this attribute type. It must not be * {@code null}. * @param description * The description for the attribute type, or * <code>null</code> if there is no description. * @param superiorType * The reference to the superior type for this attribute * type, or <code>null</code> if there is no superior * type. * @param syntax * The syntax for this attribute type, or <code>null</code> * if there is no syntax. * @param attributeUsage * The attribute usage for this attribute type, or * <code>null</code> to default to user applications. * @param isCollective * Indicates whether this attribute type is declared * "collective". * @param isNoUserModification * Indicates whether this attribute type is declared * "no-user-modification". * @param isObsolete * Indicates whether this attribute type is declared * "obsolete". * @param isSingleValue * Indicates whether this attribute type is declared * "single-value". */ public AttributeType(String definition, String primaryName, Collection<String> typeNames, String oid, String description, AttributeType superiorType, AttributeSyntax<?> syntax, AttributeUsage attributeUsage, boolean isCollective, boolean isNoUserModification, boolean isObsolete, boolean isSingleValue) { this(definition, primaryName, typeNames, oid, description, superiorType, syntax, null, null, null, null, attributeUsage, isCollective, isNoUserModification, isObsolete, isSingleValue, null); } /** * Creates a new attribute type with the provided information. * <p> * If no <code>primaryName</code> is specified, but a set of * <code>names</code> is specified, then the first name retrieved * from the set of <code>names</code> will be used as the primary * name. * * @param definition * The definition string used to create this attribute * type. It must not be {@code null}. * @param primaryName * The primary name for this attribute type, or * <code>null</code> if there is no primary name. * @param typeNames * The full set of names for this attribute type, or * <code>null</code> if there are no names. * @param oid * The OID for this attribute type. It must not be * {@code null}. * @param description * The description for the attribute type, or * <code>null</code> if there is no description. * @param superiorType * The reference to the superior type for this attribute * type, or <code>null</code> if there is no superior * type. * @param syntax * The syntax for this attribute type, or <code>null</code> * if there is no syntax. * @param approximateMatchingRule * The approximate matching rule for this attribute type, * or <code>null</code> if there is no rule. * @param equalityMatchingRule * The equality matching rule for this attribute type, or * <code>null</code> if there is no rule. * @param orderingMatchingRule * The ordering matching rule for this attribute type, or * <code>null</code> if there is no rule. * @param substringMatchingRule * The substring matching rule for this attribute type, or * <code>null</code> if there is no rule. * @param attributeUsage * The attribute usage for this attribute type, or * <code>null</code> to default to user applications. * @param isCollective * Indicates whether this attribute type is declared * "collective". * @param isNoUserModification * Indicates whether this attribute type is declared * "no-user-modification". * @param isObsolete * Indicates whether this attribute type is declared * "obsolete". * @param isSingleValue * Indicates whether this attribute type is declared * "single-value". * @param extraProperties * A set of extra properties for this attribute type, or * <code>null</code> if there are no extra properties. */ public AttributeType(String definition, String primaryName, Collection<String> typeNames, String oid, String description, AttributeType superiorType, AttributeSyntax<?> syntax, ApproximateMatchingRule approximateMatchingRule, EqualityMatchingRule equalityMatchingRule, OrderingMatchingRule orderingMatchingRule, SubstringMatchingRule substringMatchingRule, AttributeUsage attributeUsage, boolean isCollective, boolean isNoUserModification, boolean isObsolete, boolean isSingleValue, Map<String,List<String>> extraProperties) { super(primaryName, typeNames, oid, description, isObsolete, extraProperties); ensureNotNull(definition, oid); this.superiorType = superiorType; this.isCollective = isCollective; this.isNoUserModification = isNoUserModification; this.isSingleValue = isSingleValue; mayHaveSubordinateTypes = false; int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME); if (schemaFilePos > 0) { String defStr; try { int firstQuotePos = definition.indexOf('\'', schemaFilePos); int secondQuotePos = definition.indexOf('\'', firstQuotePos+1); defStr = definition.substring(0, schemaFilePos).trim() + " " + definition.substring(secondQuotePos+1).trim(); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } defStr = definition; } this.definition = defStr; } else { this.definition = definition; } if (syntax == null) { if (superiorType != null) { this.syntax = superiorType.getSyntax(); } else { this.syntax = DirectoryServer.getDefaultAttributeSyntax(); } } else { this.syntax = syntax; } syntaxOID = this.syntax.getOID(); if (approximateMatchingRule == null) { this.approximateMatchingRule = this.syntax.getApproximateMatchingRule(); } else { this.approximateMatchingRule = approximateMatchingRule; } if (equalityMatchingRule == null) { this.equalityMatchingRule = this.syntax.getEqualityMatchingRule(); } else { this.equalityMatchingRule = equalityMatchingRule; } if (orderingMatchingRule == null) { this.orderingMatchingRule = this.syntax.getOrderingMatchingRule(); } else { this.orderingMatchingRule = orderingMatchingRule; } if (substringMatchingRule == null) { this.substringMatchingRule = this.syntax.getSubstringMatchingRule(); } else { this.substringMatchingRule = substringMatchingRule; } if (attributeUsage != null) { this.attributeUsage = attributeUsage; } else { this.attributeUsage = AttributeUsage.USER_APPLICATIONS; } if (oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID)) { isObjectClassType = true; } else { isObjectClassType = hasName(OBJECTCLASS_ATTRIBUTE_TYPE_NAME); } isOperational = this.attributeUsage.isOperational(); } /** * Retrieves the definition string used to create this attribute * type. * * @return The definition string used to create this attribute * type. */ public String getDefinition() { return definition; } /** * Retrieves the definition string used to create this attribute * type and including the X-SCHEMA-FILE extension. * * @return The definition string used to create this attribute * type including the X-SCHEMA-FILE extension. */ public String getDefinitionWithFileName() { if (getSchemaFile() != null) { int pos = definition.lastIndexOf(')'); String defStr = definition.substring(0, pos).trim() + " " + SCHEMA_PROPERTY_FILENAME + " '" + getSchemaFile() + "' )"; return defStr; } else return definition; } /** * {@inheritDoc} */ public AttributeType recreateFromDefinition(Schema schema) throws DirectoryException { ByteString value = ByteString.valueOf(definition); AttributeType at = AttributeTypeSyntax.decodeAttributeType(value, schema, false); at.setSchemaFile(getSchemaFile()); at.mayHaveSubordinateTypes = mayHaveSubordinateTypes; return at; } /** * Retrieves the superior type for this attribute type. * * @return The superior type for this attribute type, or * <CODE>null</CODE> if it does not have one. */ public AttributeType getSuperiorType() { return superiorType; } /** * Indicates whether there is a possibility that this attribute type * may have one or more subordinate attribute types defined in the * server schema. This is only intended for use by the * {@code org.opends.server.types.Entry} class for the purpose of * determining whether to check for subtypes when retrieving * attributes. Note that it is possible for this method to report * false positives (if an attribute type that previously had one or * more subordinate types no longer has any), but not false * negatives. * * @return {@code true} if the {@code hasSubordinateTypes} flag has * been set for this attribute type at any time since * startup, or {@code false} if not. */ boolean mayHaveSubordinateTypes() { return mayHaveSubordinateTypes; } /** * Sets a flag indicating that this attribute type may have one or * more subordinate attribute types defined in the server schema. * This is only intended for use by the * {@code org.opends.server.types.Schema} class. */ void setMayHaveSubordinateTypes() { mayHaveSubordinateTypes = true; } /** * Retrieves the syntax for this attribute type. * * @return The syntax for this attribute type. */ public AttributeSyntax<?> getSyntax() { return syntax; } /** * Indicates whether this attribute syntax requires BER encoding. * * @return {@code true} if this syntax required BER encoding. */ public boolean isBinary() { return syntax.isBinary(); } /** * Indicates whether this attribute syntax is human readable. * * @return {@code true} if this syntax is human readable. */ public boolean isHumanReadable() { return syntax.isHumanReadable(); } /** * Retrieves the OID for this syntax associated with this attribute * type. * * @return The OID for this syntax associated with this attribute * type. */ public String getSyntaxOID() { return syntaxOID; } /** * Retrieves the matching rule that should be used for approximate * matching with this attribute type. * * @return The matching rule that should be used for approximate * matching with this attribute type. */ public ApproximateMatchingRule getApproximateMatchingRule() { return approximateMatchingRule; } /** * Retrieves the matching rule that should be used for equality * matching with this attribute type. * * @return The matching rule that should be used for equality * matching with this attribute type. */ public EqualityMatchingRule getEqualityMatchingRule() { return equalityMatchingRule; } /** * Retrieves the matching rule that should be used for ordering with * this attribute type. * * @return The matching rule that should be used for ordering with * this attribute type. */ public OrderingMatchingRule getOrderingMatchingRule() { return orderingMatchingRule; } /** * Retrieves the matching rule that should be used for substring * matching with this attribute type. * * @return The matching rule that should be used for substring * matching with this attribute type. */ public SubstringMatchingRule getSubstringMatchingRule() { return substringMatchingRule; } /** * Retrieves the usage indicator for this attribute type. * * @return The usage indicator for this attribute type. */ public AttributeUsage getUsage() { return attributeUsage; } /** * Indicates whether this is an operational attribute. An * operational attribute is one with a usage of * "directoryOperation", "distributedOperation", or "dSAOperation" * (i.e., only userApplications is not operational). * * @return <CODE>true</CODE> if this is an operational attribute, * or <CODE>false</CODE> if not. */ public boolean isOperational() { return isOperational; } /** * Indicates whether this attribute type is declared "collective". * * @return <CODE>true</CODE> if this attribute type is declared * "collective", or <CODE>false</CODE> if not. */ public boolean isCollective() { return isCollective; } /** * Indicates whether this attribute type is declared * "no-user-modification". * * @return <CODE>true</CODE> if this attribute type is declared * "no-user-modification", or <CODE>false</CODE> if not. */ public boolean isNoUserModification() { return isNoUserModification; } /** * Indicates whether this attribute type is declared "single-value". * * @return <CODE>true</CODE> if this attribute type is declared * "single-value", or <CODE>false</CODE> if not. */ public boolean isSingleValue() { return isSingleValue; } /** * Indicates whether this attribute type represents the * "objectclass" attribute. The determination will be made based on * the name and/or OID. * * @return <CODE>true</CODE> if this attribute type is the * objectclass type, or <CODE>false</CODE> if not. */ public boolean isObjectClassType() { return isObjectClassType; } /** * Appends a string representation of this schema definition's * non-generic properties to the provided buffer. * * @param buffer The buffer to which the information should be * appended. */ protected void toStringContent(StringBuilder buffer) { if (superiorType != null) { buffer.append(" SUP "); buffer.append(superiorType.getNameOrOID()); } if (equalityMatchingRule != null) { buffer.append(" EQUALITY "); buffer.append(equalityMatchingRule.getNameOrOID()); } if (orderingMatchingRule != null) { buffer.append(" ORDERING "); buffer.append(orderingMatchingRule.getNameOrOID()); } if (substringMatchingRule != null) { buffer.append(" SUBSTR "); buffer.append(substringMatchingRule.getNameOrOID()); } // NOTE -- We will not include any approximate matching rule // information here because it would break the standard and // anything that depends on it. // FIXME -- Should we encode this into one of the "extra" // properties? if (syntax != null) { buffer.append(" SYNTAX "); buffer.append(syntax.getOID()); } if (isSingleValue) { buffer.append(" SINGLE-VALUE"); } if (isCollective) { buffer.append(" COLLECTIVE"); } if (isNoUserModification) { buffer.append(" NO-USER-MODIFICATION"); } if (attributeUsage != null) { buffer.append(" USAGE "); buffer.append(attributeUsage.toString()); } } /** * {@inheritDoc} */ public int compareTo(AttributeType o) { return getNormalizedPrimaryNameOrOID().compareTo( o.getNormalizedPrimaryNameOrOID()); } /** * Marks this attribute type as dirty, indicating that it has been removed or * replaced in the schema. * * @return A reference to this attribute type. */ public AttributeType setDirty() { isDirty = true; return this; } /** * Returns {@code true} if this attribute type has been removed or replaced in * the schema. * * @return {@code true} if this attribute type has been removed or replaced in * the schema. */ public boolean isDirty() { return isDirty; } }