/* * 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 2009 Sun Microsystems, Inc. */ package org.opends.sdk.schema; import static com.sun.opends.sdk.messages.Messages.*; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.opends.sdk.*; import org.opends.sdk.requests.Requests; import org.opends.sdk.requests.SearchRequest; import org.opends.sdk.responses.Responses; import org.opends.sdk.responses.Result; import org.opends.sdk.responses.SearchResultEntry; import com.sun.opends.sdk.util.FutureResultTransformer; import com.sun.opends.sdk.util.RecursiveFutureResult; import com.sun.opends.sdk.util.StaticUtils; /** * This class defines a data structure that holds information about the * components of the LDAP schema. It includes the following kinds of * elements: * */ public final class Schema { private static class EmptyImpl implements Impl { private final SchemaCompatOptions options; private EmptyImpl() { this.options = SchemaCompatOptions.defaultOptions(); } public AttributeType getAttributeType(String name) { // Construct an placeholder attribute type with the given name, // the default matching rule, and the default syntax. The OID of // the attribute will be the normalized OID alias with "-oid" // appended to the given name. final StringBuilder builder = new StringBuilder(name.length() + 4); StaticUtils.toLowerCase(name, builder); builder.append("-oid"); final String noid = builder.toString(); return new AttributeType(noid, Collections.singletonList(name), "", Schema.getDefaultMatchingRule(), Schema .getDefaultSyntax()); } public Collection getAttributeTypes() { return Collections.emptyList(); } public List getAttributeTypesByName(String name) { return Collections.emptyList(); } public DITContentRule getDITContentRule(String name) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_DCR_UNKNOWN .get(name)); } public Collection getDITContentRules() { return Collections.emptyList(); } public Collection getDITContentRulesByName( String name) { return Collections.emptyList(); } public DITStructureRule getDITStructureRule(int ruleID) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_DSR_UNKNOWN .get(String.valueOf(ruleID))); } public Collection getDITStructureRulesByName( String name) { return Collections.emptyList(); } public Collection getDITStructureRulesByNameForm( NameForm nameForm) { return Collections.emptyList(); } public Collection getDITStuctureRules() { return Collections.emptyList(); } public MatchingRule getMatchingRule(String name) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_MR_UNKNOWN.get(name)); } public Collection getMatchingRules() { return Collections.emptyList(); } public Collection getMatchingRulesByName(String name) { return Collections.emptyList(); } public MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule) throws UnknownSchemaElementException { return getMatchingRuleUse(matchingRule.getOID()); } public MatchingRuleUse getMatchingRuleUse(String name) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_MRU_UNKNOWN .get(name)); } public Collection getMatchingRuleUses() { return Collections.emptyList(); } public Collection getMatchingRuleUsesByName( String name) { return Collections.emptyList(); } public NameForm getNameForm(String name) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_NAMEFORM_UNKNOWN .get(name)); } public Collection getNameFormByObjectClass( ObjectClass structuralClass) { return Collections.emptyList(); } public Collection getNameForms() { return Collections.emptyList(); } public Collection getNameFormsByName(String name) { return Collections.emptyList(); } public ObjectClass getObjectClass(String name) throws UnknownSchemaElementException { throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN .get(name)); } public Collection getObjectClasses() { return Collections.emptyList(); } public Collection getObjectClassesByName(String name) { return Collections.emptyList(); } public SchemaCompatOptions getSchemaCompatOptions() { return options; } /** * {@inheritDoc} */ public String getSchemaName() { return "Empty Schema"; } public Syntax getSyntax(String numericOID) { // Fake up a syntax substituted by the default syntax. return new Syntax(numericOID); } public Collection getSyntaxes() { return Collections.emptyList(); } public Collection getWarnings() { return Collections.emptyList(); } public boolean hasAttributeType(String name) { // In theory a non-strict schema always contains the requested // attribute type, so we could always return true. However, we // should provide a way for callers to differentiate between a // real attribute type and a faked up attribute type. return false; } public boolean hasDITContentRule(String name) { return false; } public boolean hasDITStructureRule(int ruleID) { return false; } public boolean hasMatchingRule(String name) { return false; } public boolean hasMatchingRuleUse(String name) { return false; } public boolean hasNameForm(String name) { return false; } public boolean hasObjectClass(String name) { return false; } public boolean hasSyntax(String numericOID) { return false; } public boolean isStrict() { return false; } } private static interface Impl { AttributeType getAttributeType(String name) throws UnknownSchemaElementException; Collection getAttributeTypes(); List getAttributeTypesByName(String name); DITContentRule getDITContentRule(String name) throws UnknownSchemaElementException; Collection getDITContentRules(); Collection getDITContentRulesByName(String name); DITStructureRule getDITStructureRule(int ruleID) throws UnknownSchemaElementException; Collection getDITStructureRulesByName(String name); Collection getDITStructureRulesByNameForm( NameForm nameForm); Collection getDITStuctureRules(); MatchingRule getMatchingRule(String name) throws UnknownSchemaElementException; Collection getMatchingRules(); Collection getMatchingRulesByName(String name); MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule) throws UnknownSchemaElementException; MatchingRuleUse getMatchingRuleUse(String name) throws UnknownSchemaElementException; Collection getMatchingRuleUses(); Collection getMatchingRuleUsesByName(String name); NameForm getNameForm(String name) throws UnknownSchemaElementException; Collection getNameFormByObjectClass( ObjectClass structuralClass); Collection getNameForms(); Collection getNameFormsByName(String name); ObjectClass getObjectClass(String name) throws UnknownSchemaElementException; Collection getObjectClasses(); Collection getObjectClassesByName(String name); SchemaCompatOptions getSchemaCompatOptions(); String getSchemaName(); Syntax getSyntax(String numericOID) throws UnknownSchemaElementException; Collection getSyntaxes(); Collection getWarnings(); boolean hasAttributeType(String name); boolean hasDITContentRule(String name); boolean hasDITStructureRule(int ruleID); boolean hasMatchingRule(String name); boolean hasMatchingRuleUse(String name); boolean hasNameForm(String name); boolean hasObjectClass(String name); boolean hasSyntax(String numericOID); boolean isStrict(); } private static class NonStrictImpl implements Impl { private final Impl strictImpl; private NonStrictImpl(Impl strictImpl) { this.strictImpl = strictImpl; } public AttributeType getAttributeType(String name) throws UnknownSchemaElementException { if (!strictImpl.hasAttributeType(name)) { // Construct an placeholder attribute type with the given name, // the default matching rule, and the default syntax. The OID of // the attribute will be the normalized OID alias with "-oid" // appended to the given name. final StringBuilder builder = new StringBuilder( name.length() + 4); StaticUtils.toLowerCase(name, builder); builder.append("-oid"); final String noid = builder.toString(); return new AttributeType(noid, Collections.singletonList(name), "", Schema.getDefaultMatchingRule(), Schema .getDefaultSyntax()); } return strictImpl.getAttributeType(name); } public Collection getAttributeTypes() { return strictImpl.getAttributeTypes(); } public List getAttributeTypesByName(String name) { return strictImpl.getAttributeTypesByName(name); } public DITContentRule getDITContentRule(String name) throws UnknownSchemaElementException { return strictImpl.getDITContentRule(name); } public Collection getDITContentRules() { return strictImpl.getDITContentRules(); } public Collection getDITContentRulesByName( String name) { return strictImpl.getDITContentRulesByName(name); } public DITStructureRule getDITStructureRule(int ruleID) throws UnknownSchemaElementException { return strictImpl.getDITStructureRule(ruleID); } public Collection getDITStructureRulesByName( String name) { return strictImpl.getDITStructureRulesByName(name); } public Collection getDITStructureRulesByNameForm( NameForm nameForm) { return strictImpl.getDITStructureRulesByNameForm(nameForm); } public Collection getDITStuctureRules() { return strictImpl.getDITStuctureRules(); } public MatchingRule getMatchingRule(String name) throws UnknownSchemaElementException { return strictImpl.getMatchingRule(name); } public Collection getMatchingRules() { return strictImpl.getMatchingRules(); } public Collection getMatchingRulesByName(String name) { return strictImpl.getMatchingRulesByName(name); } public MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule) throws UnknownSchemaElementException { return strictImpl.getMatchingRuleUse(matchingRule); } public MatchingRuleUse getMatchingRuleUse(String name) throws UnknownSchemaElementException { return strictImpl.getMatchingRuleUse(name); } public Collection getMatchingRuleUses() { return strictImpl.getMatchingRuleUses(); } public Collection getMatchingRuleUsesByName( String name) { return strictImpl.getMatchingRuleUsesByName(name); } public NameForm getNameForm(String name) throws UnknownSchemaElementException { return strictImpl.getNameForm(name); } public Collection getNameFormByObjectClass( ObjectClass structuralClass) { return strictImpl.getNameFormByObjectClass(structuralClass); } public Collection getNameForms() { return strictImpl.getNameForms(); } public Collection getNameFormsByName(String name) { return strictImpl.getNameFormsByName(name); } public ObjectClass getObjectClass(String name) throws UnknownSchemaElementException { return strictImpl.getObjectClass(name); } public Collection getObjectClasses() { return strictImpl.getObjectClasses(); } public Collection getObjectClassesByName(String name) { return strictImpl.getObjectClassesByName(name); } public SchemaCompatOptions getSchemaCompatOptions() { return strictImpl.getSchemaCompatOptions(); } public String getSchemaName() { return strictImpl.getSchemaName(); } public Syntax getSyntax(String numericOID) { if (!strictImpl.hasSyntax(numericOID)) { return new Syntax(numericOID); } return strictImpl.getSyntax(numericOID); } public Collection getSyntaxes() { return strictImpl.getSyntaxes(); } public Collection getWarnings() { return strictImpl.getWarnings(); } public boolean hasAttributeType(String name) { // In theory a non-strict schema always contains the requested // attribute type, so we could always return true. However, we // should provide a way for callers to differentiate between a // real attribute type and a faked up attribute type. return strictImpl.hasAttributeType(name); } public boolean hasDITContentRule(String name) { return strictImpl.hasDITContentRule(name); } public boolean hasDITStructureRule(int ruleID) { return strictImpl.hasDITStructureRule(ruleID); } public boolean hasMatchingRule(String name) { return strictImpl.hasMatchingRule(name); } public boolean hasMatchingRuleUse(String name) { return strictImpl.hasMatchingRuleUse(name); } public boolean hasNameForm(String name) { return strictImpl.hasNameForm(name); } public boolean hasObjectClass(String name) { return strictImpl.hasObjectClass(name); } public boolean hasSyntax(String numericOID) { return strictImpl.hasSyntax(numericOID); } public boolean isStrict() { return false; } } private static class StrictImpl implements Impl { private final Map id2StructureRules; private final Map> name2AttributeTypes; private final Map> name2ContentRules; private final Map> name2MatchingRules; private final Map> name2MatchingRuleUses; private final Map> name2NameForms; private final Map> name2ObjectClasses; private final Map> name2StructureRules; private final Map> nameForm2StructureRules; private final Map numericOID2AttributeTypes; private final Map numericOID2ContentRules; private final Map numericOID2MatchingRules; private final Map numericOID2MatchingRuleUses; private final Map numericOID2NameForms; private final Map numericOID2ObjectClasses; private final Map numericOID2Syntaxes; private final Map> objectClass2NameForms; private final SchemaCompatOptions options; private final List warnings; private final String schemaName; private StrictImpl(String schemaName, Map numericOID2Syntaxes, Map numericOID2MatchingRules, Map numericOID2MatchingRuleUses, Map numericOID2AttributeTypes, Map numericOID2ObjectClasses, Map numericOID2NameForms, Map numericOID2ContentRules, Map id2StructureRules, Map> name2MatchingRules, Map> name2MatchingRuleUses, Map> name2AttributeTypes, Map> name2ObjectClasses, Map> name2NameForms, Map> name2ContentRules, Map> name2StructureRules, Map> objectClass2NameForms, Map> nameForm2StructureRules, SchemaCompatOptions options, List warnings) { this.schemaName = schemaName; this.numericOID2Syntaxes = Collections .unmodifiableMap(numericOID2Syntaxes); this.numericOID2MatchingRules = Collections .unmodifiableMap(numericOID2MatchingRules); this.numericOID2MatchingRuleUses = Collections .unmodifiableMap(numericOID2MatchingRuleUses); this.numericOID2AttributeTypes = Collections .unmodifiableMap(numericOID2AttributeTypes); this.numericOID2ObjectClasses = Collections .unmodifiableMap(numericOID2ObjectClasses); this.numericOID2NameForms = Collections .unmodifiableMap(numericOID2NameForms); this.numericOID2ContentRules = Collections .unmodifiableMap(numericOID2ContentRules); this.id2StructureRules = Collections .unmodifiableMap(id2StructureRules); this.name2MatchingRules = Collections .unmodifiableMap(name2MatchingRules); this.name2MatchingRuleUses = Collections .unmodifiableMap(name2MatchingRuleUses); this.name2AttributeTypes = Collections .unmodifiableMap(name2AttributeTypes); this.name2ObjectClasses = Collections .unmodifiableMap(name2ObjectClasses); this.name2NameForms = Collections.unmodifiableMap(name2NameForms); this.name2ContentRules = Collections .unmodifiableMap(name2ContentRules); this.name2StructureRules = Collections .unmodifiableMap(name2StructureRules); this.objectClass2NameForms = Collections .unmodifiableMap(objectClass2NameForms); this.nameForm2StructureRules = Collections .unmodifiableMap(nameForm2StructureRules); this.options = options; this.warnings = Collections.unmodifiableList(warnings); } public AttributeType getAttributeType(String name) throws UnknownSchemaElementException { final AttributeType type = numericOID2AttributeTypes.get(name); if (type != null) { return type; } final List attributes = name2AttributeTypes .get(StaticUtils.toLowerCase(name)); if (attributes != null) { if (attributes.size() == 1) { return attributes.get(0); } throw new UnknownSchemaElementException( WARN_ATTR_TYPE_AMBIGIOUS.get(name)); } throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN .get(name)); } public Collection getAttributeTypes() { return numericOID2AttributeTypes.values(); } public List getAttributeTypesByName(String name) { final List attributes = name2AttributeTypes .get(StaticUtils.toLowerCase(name)); if (attributes == null) { return Collections.emptyList(); } else { return attributes; } } public DITContentRule getDITContentRule(String name) throws UnknownSchemaElementException { final DITContentRule rule = numericOID2ContentRules.get(name); if (rule != null) { return rule; } final List rules = name2ContentRules .get(StaticUtils.toLowerCase(name)); if (rules != null) { if (rules.size() == 1) { return rules.get(0); } throw new UnknownSchemaElementException(WARN_DCR_AMBIGIOUS .get(name)); } throw new UnknownSchemaElementException(WARN_DCR_UNKNOWN .get(name)); } public Collection getDITContentRules() { return numericOID2ContentRules.values(); } public Collection getDITContentRulesByName( String name) { final List rules = name2ContentRules .get(StaticUtils.toLowerCase(name)); if (rules == null) { return Collections.emptyList(); } else { return rules; } } public DITStructureRule getDITStructureRule(int ruleID) throws UnknownSchemaElementException { final DITStructureRule rule = id2StructureRules.get(ruleID); if (rule == null) { throw new UnknownSchemaElementException(WARN_DSR_UNKNOWN .get(String.valueOf(ruleID))); } return rule; } public Collection getDITStructureRulesByName( String name) { final List rules = name2StructureRules .get(StaticUtils.toLowerCase(name)); if (rules == null) { return Collections.emptyList(); } else { return rules; } } public Collection getDITStructureRulesByNameForm( NameForm nameForm) { final List rules = nameForm2StructureRules .get(nameForm.getOID()); if (rules == null) { return Collections.emptyList(); } else { return rules; } } public Collection getDITStuctureRules() { return id2StructureRules.values(); } public MatchingRule getMatchingRule(String name) throws UnknownSchemaElementException { final MatchingRule rule = numericOID2MatchingRules.get(name); if (rule != null) { return rule; } final List rules = name2MatchingRules .get(StaticUtils.toLowerCase(name)); if (rules != null) { if (rules.size() == 1) { return rules.get(0); } throw new UnknownSchemaElementException(WARN_MR_AMBIGIOUS .get(name)); } throw new UnknownSchemaElementException(WARN_MR_UNKNOWN.get(name)); } public Collection getMatchingRules() { return numericOID2MatchingRules.values(); } public Collection getMatchingRulesByName(String name) { final List rules = name2MatchingRules .get(StaticUtils.toLowerCase(name)); if (rules == null) { return Collections.emptyList(); } else { return rules; } } public MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule) throws UnknownSchemaElementException { return getMatchingRuleUse(matchingRule.getOID()); } public MatchingRuleUse getMatchingRuleUse(String name) throws UnknownSchemaElementException { final MatchingRuleUse rule = numericOID2MatchingRuleUses .get(name); if (rule != null) { return rule; } final List uses = name2MatchingRuleUses .get(StaticUtils.toLowerCase(name)); if (uses != null) { if (uses.size() == 1) { return uses.get(0); } throw new UnknownSchemaElementException(WARN_MRU_AMBIGIOUS .get(name)); } throw new UnknownSchemaElementException(WARN_MRU_UNKNOWN .get(name)); } public Collection getMatchingRuleUses() { return numericOID2MatchingRuleUses.values(); } public Collection getMatchingRuleUsesByName( String name) { final List rules = name2MatchingRuleUses .get(StaticUtils.toLowerCase(name)); if (rules == null) { return Collections.emptyList(); } else { return rules; } } public NameForm getNameForm(String name) throws UnknownSchemaElementException { final NameForm form = numericOID2NameForms.get(name); if (form != null) { return form; } final List forms = name2NameForms.get(StaticUtils .toLowerCase(name)); if (forms != null) { if (forms.size() == 1) { return forms.get(0); } throw new UnknownSchemaElementException(WARN_NAMEFORM_AMBIGIOUS .get(name)); } throw new UnknownSchemaElementException(WARN_NAMEFORM_UNKNOWN .get(name)); } public Collection getNameFormByObjectClass( ObjectClass structuralClass) { final List forms = objectClass2NameForms .get(structuralClass.getOID()); if (forms == null) { return Collections.emptyList(); } else { return forms; } } public Collection getNameForms() { return numericOID2NameForms.values(); } public Collection getNameFormsByName(String name) { final List forms = name2NameForms.get(StaticUtils .toLowerCase(name)); if (forms == null) { return Collections.emptyList(); } else { return forms; } } public ObjectClass getObjectClass(String name) throws UnknownSchemaElementException { final ObjectClass oc = numericOID2ObjectClasses.get(name); if (oc != null) { return oc; } final List classes = name2ObjectClasses .get(StaticUtils.toLowerCase(name)); if (classes != null) { if (classes.size() == 1) { return classes.get(0); } throw new UnknownSchemaElementException( WARN_OBJECTCLASS_AMBIGIOUS.get(name)); } throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN .get(name)); } public Collection getObjectClasses() { return numericOID2ObjectClasses.values(); } public Collection getObjectClassesByName(String name) { final List classes = name2ObjectClasses .get(StaticUtils.toLowerCase(name)); if (classes == null) { return Collections.emptyList(); } else { return classes; } } public SchemaCompatOptions getSchemaCompatOptions() { return options; } public String getSchemaName() { return schemaName; } public Syntax getSyntax(String numericOID) throws UnknownSchemaElementException { final Syntax syntax = numericOID2Syntaxes.get(numericOID); if (syntax == null) { throw new UnknownSchemaElementException(WARN_SYNTAX_UNKNOWN .get(numericOID)); } return syntax; } public Collection getSyntaxes() { return numericOID2Syntaxes.values(); } public Collection getWarnings() { return warnings; } public boolean hasAttributeType(String name) { if (numericOID2AttributeTypes.containsKey(name)) { return true; } final List attributes = name2AttributeTypes .get(StaticUtils.toLowerCase(name)); return attributes != null && attributes.size() == 1; } public boolean hasDITContentRule(String name) { if (numericOID2ContentRules.containsKey(name)) { return true; } final List rules = name2ContentRules .get(StaticUtils.toLowerCase(name)); return rules != null && rules.size() == 1; } public boolean hasDITStructureRule(int ruleID) { return id2StructureRules.containsKey(ruleID); } public boolean hasMatchingRule(String name) { if (numericOID2MatchingRules.containsKey(name)) { return true; } final List rules = name2MatchingRules .get(StaticUtils.toLowerCase(name)); return rules != null && rules.size() == 1; } public boolean hasMatchingRuleUse(String name) { if (numericOID2MatchingRuleUses.containsKey(name)) { return true; } final List uses = name2MatchingRuleUses .get(StaticUtils.toLowerCase(name)); return uses != null && uses.size() == 1; } public boolean hasNameForm(String name) { if (numericOID2NameForms.containsKey(name)) { return true; } final List forms = name2NameForms.get(StaticUtils .toLowerCase(name)); return forms != null && forms.size() == 1; } public boolean hasObjectClass(String name) { if (numericOID2ObjectClasses.containsKey(name)) { return true; } final List classes = name2ObjectClasses .get(StaticUtils.toLowerCase(name)); return classes != null && classes.size() == 1; } public boolean hasSyntax(String numericOID) { return numericOID2Syntaxes.containsKey(numericOID); } public boolean isStrict() { return true; } } private static final Schema CORE_SCHEMA = CoreSchemaImpl .getInstance(); private static final Schema EMPTY_SCHEMA = new Schema(new EmptyImpl()); private static volatile Schema DEFAULT_SCHEMA = CoreSchemaImpl .getInstance(); private static final AttributeDescription ATTR_ATTRIBUTE_TYPES = AttributeDescription .valueOf("attributeTypes"); private static final AttributeDescription ATTR_DIT_CONTENT_RULES = AttributeDescription .valueOf("dITContentRules"); private static final AttributeDescription ATTR_DIT_STRUCTURE_RULES = AttributeDescription .valueOf("dITStructureRules"); private static final AttributeDescription ATTR_LDAP_SYNTAXES = AttributeDescription .valueOf("ldapSyntaxes"); private static final AttributeDescription ATTR_MATCHING_RULE_USE = AttributeDescription .valueOf("matchingRuleUse"); private static final AttributeDescription ATTR_MATCHING_RULES = AttributeDescription .valueOf("matchingRules"); private static final AttributeDescription ATTR_NAME_FORMS = AttributeDescription .valueOf("nameForms"); private static final AttributeDescription ATTR_OBJECT_CLASSES = AttributeDescription .valueOf("objectClasses"); private static final AttributeDescription ATTR_SUBSCHEMA_SUBENTRY = AttributeDescription .valueOf("subschemaSubentry"); private static final String[] SUBSCHEMA_ATTRS = new String[] { ATTR_LDAP_SYNTAXES.toString(), ATTR_ATTRIBUTE_TYPES.toString(), ATTR_DIT_CONTENT_RULES.toString(), ATTR_DIT_STRUCTURE_RULES.toString(), ATTR_MATCHING_RULE_USE.toString(), ATTR_MATCHING_RULES.toString(), ATTR_NAME_FORMS.toString(), ATTR_OBJECT_CLASSES.toString() }; private static final Filter SUBSCHEMA_FILTER = Filter .newEqualityMatchFilter(CoreSchema.getObjectClassAttributeType() .getNameOrOID(), CoreSchema.getSubschemaObjectClass() .getNameOrOID()); private static final String[] SUBSCHEMA_SUBENTRY_ATTRS = new String[] { ATTR_SUBSCHEMA_SUBENTRY .toString() }; /** * Returns the core schema. The core schema is non-strict and contains * the following standard LDAP schema elements: * * * @return The core schema. */ public static Schema getCoreSchema() { return CORE_SCHEMA; } /** * Returns the default schema which should be used by this * application. The default schema is initially set to the core * schema. * * @return The default schema which should be used by this * application. */ public static Schema getDefaultSchema() { return DEFAULT_SCHEMA; } /** * Returns the empty schema. The empty schema is non-strict and does * not contain any schema elements. * * @return The empty schema. */ public static Schema getEmptySchema() { return EMPTY_SCHEMA; } /** * Reads the schema from the Directory Server contained in the named * subschema sub-entry. *

* If the requested schema is not returned by the Directory Server * then the request will fail with an {@link EntryNotFoundException}. * More specifically, the returned future will never return {@code * null}. *

* Implementations may choose to perform optimizations such as * caching. * * @param connection * A connection to the Directory Server whose schema is to be * read. * @param name * The distinguished name of the subschema sub-entry. * @param handler * A result handler which can be used to asynchronously * process the operation result when it is received, may be * {@code null}. * @return A future representing the result of the operation. * @throws UnsupportedOperationException * If this connection does not support search operations. * @throws IllegalStateException * If this connection has already been closed, i.e. if * {@code isClosed() == true}. * @throws NullPointerException * If the {@code connection} or {@code name} was {@code * null}. */ public static FutureResult readSchema( AsynchronousConnection connection, DN name, ResultHandler handler) throws UnsupportedOperationException, IllegalStateException, NullPointerException { final SearchRequest request = getReadSchemaSearchRequest(name); final FutureResultTransformer future = new FutureResultTransformer( handler) { protected Schema transformResult(SearchResultEntry result) throws ErrorResultException { return valueOf(result); } }; final FutureResult innerFuture = connection .searchSingleEntry(request, future); future.setFutureResult(innerFuture); return future; } /** * Reads the schema from the Directory Server contained in the named * subschema sub-entry using the provided connection. *

* If the requested schema is not returned by the Directory Server * then the request will fail with an {@link EntryNotFoundException}. * More specifically, this method will never return {@code null}. * * @param connection * A connection to the Directory Server whose schema is to be * read. * @param name * The distinguished name of the subschema sub-entry. * @return The schema from the Directory Server. * @throws ErrorResultException * If the result code indicates that the request failed for * some reason. * @throws InterruptedException * If the current thread was interrupted while waiting. * @throws UnsupportedOperationException * If the connection does not support search operations. * @throws IllegalStateException * If the connection has already been closed, i.e. if * {@code isClosed() == true}. * @throws NullPointerException * If the {@code connection} or {@code name} was {@code * null}. */ public static Schema readSchema(Connection connection, DN name) throws ErrorResultException, InterruptedException, UnsupportedOperationException, IllegalStateException, NullPointerException { final SearchRequest request = getReadSchemaSearchRequest(name); final Entry entry = connection.searchSingleEntry(request); return valueOf(entry); } /** * Reads the schema from the Directory Server which applies to the * named entry. *

* If the requested entry or its associated schema are not returned by * the Directory Server then the request will fail with an * {@link EntryNotFoundException}. More specifically, the returned * future will never return {@code null}. *

* A typical implementation will first read the {@code * subschemaSubentry} attribute of the entry in order to locate the * schema. However, implementations may choose to perform other * optimizations, such as caching. * * @param connection * A connection to the Directory Server whose schema is to be * read. * @param name * The distinguished name of the entry whose schema is to be * located. * @param handler * A result handler which can be used to asynchronously * process the operation result when it is received, may be * {@code null}. * @return A future representing the result of the operation. * @throws UnsupportedOperationException * If this connection does not support search operations. * @throws IllegalStateException * If this connection has already been closed, i.e. if * {@code isClosed() == true}. * @throws NullPointerException * If the {@code connection} or {@code name} was {@code * null}. */ public static FutureResult readSchemaForEntry( final AsynchronousConnection connection, final DN name, ResultHandler handler) throws UnsupportedOperationException, IllegalStateException, NullPointerException { final RecursiveFutureResult future = new RecursiveFutureResult( handler) { protected FutureResult chainResult( SearchResultEntry innerResult, ResultHandler handler) throws ErrorResultException { final DN subschemaDN = getSubschemaSubentryDN(name, innerResult); return readSchema(connection, subschemaDN, handler); } }; final SearchRequest request = getReadSchemaForEntrySearchRequest(name); final FutureResult innerFuture = connection .searchSingleEntry(request, future); future.setFutureResult(innerFuture); return future; } /** * Reads the schema from the Directory Server which applies to the * named entry using the provided connection. *

* If the requested entry or its associated schema are not returned by * the Directory Server then the request will fail with an * {@link EntryNotFoundException}. More specifically, this method will * never return {@code null}. *

* A typical implementation will first read the {@code * subschemaSubentry} attribute of the entry in order to locate the * schema. However, implementations may choose to perform other * optimizations, such as caching. * * @param connection * A connection to the Directory Server whose schema is to be * read. * @param name * The distinguished name of the entry whose schema is to be * located. * @return The schema from the Directory Server which applies to the * named entry. * @throws ErrorResultException * If the result code indicates that the request failed for * some reason. * @throws InterruptedException * If the current thread was interrupted while waiting. * @throws UnsupportedOperationException * If the connection does not support search operations. * @throws IllegalStateException * If the connection has already been closed, i.e. if * {@code isClosed() == true}. * @throws NullPointerException * If the {@code connection} or {@code name} was {@code * null}. */ public static Schema readSchemaForEntry(Connection connection, DN name) throws ErrorResultException, InterruptedException, UnsupportedOperationException, IllegalStateException, NullPointerException { final SearchRequest request = getReadSchemaForEntrySearchRequest(name); final Entry entry = connection.searchSingleEntry(request); final DN subschemaDN = getSubschemaSubentryDN(name, entry); return readSchema(connection, subschemaDN); } /** * Sets the default schema which should be used by this application. * The default schema is initially set to the core schema. * * @param schema * The default schema which should be used by this * application. */ public static void setDefaultSchema(Schema schema) { DEFAULT_SCHEMA = schema; } /** * Parses the provided entry as a subschema subentry. Any problems * encountered while parsing the entry can be retrieved using the * returned schema's {@link #getWarnings()} method. * * @param entry * The subschema subentry to be parsed. * @return The parsed schema. */ public static Schema valueOf(Entry entry) { final SchemaBuilder builder = new SchemaBuilder(entry.getName() .toString()); Attribute attr = entry.getAttribute(ATTR_LDAP_SYNTAXES); if (attr != null) { for (final ByteString def : attr) { try { builder.addSyntax(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_ATTRIBUTE_TYPES); if (attr != null) { for (final ByteString def : attr) { try { builder.addAttributeType(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_OBJECT_CLASSES); if (attr != null) { for (final ByteString def : attr) { try { builder.addObjectClass(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_MATCHING_RULE_USE); if (attr != null) { for (final ByteString def : attr) { try { builder.addMatchingRuleUse(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_MATCHING_RULES); if (attr != null) { for (final ByteString def : attr) { try { builder.addMatchingRule(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_DIT_CONTENT_RULES); if (attr != null) { for (final ByteString def : attr) { try { builder.addDITContentRule(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_DIT_STRUCTURE_RULES); if (attr != null) { for (final ByteString def : attr) { try { builder.addDITStructureRule(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } attr = entry.getAttribute(ATTR_NAME_FORMS); if (attr != null) { for (final ByteString def : attr) { try { builder.addNameForm(def.toString(), true); } catch (final LocalizedIllegalArgumentException e) { builder.addWarning(e.getMessageObject()); } } } return builder.toSchema(); } // Constructs a search request for retrieving the subschemaSubentry // attribute from the named entry. private static SearchRequest getReadSchemaForEntrySearchRequest(DN dn) { return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter(), SUBSCHEMA_SUBENTRY_ATTRS); } // Constructs a search request for retrieving the named subschema // sub-entry. private static SearchRequest getReadSchemaSearchRequest(DN dn) { return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS); } private static DN getSubschemaSubentryDN(DN name, final Entry entry) throws ErrorResultException { final Attribute subentryAttr = entry .getAttribute(ATTR_SUBSCHEMA_SUBENTRY); if (subentryAttr == null || subentryAttr.isEmpty()) { // Did not get the subschema sub-entry attribute. final Result result = Responses.newResult( ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED) .setDiagnosticMessage( ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString()) .toString()); throw ErrorResultException.wrap(result); } final String dnString = subentryAttr.iterator().next().toString(); DN subschemaDN; try { subschemaDN = DN.valueOf(dnString); } catch (final LocalizedIllegalArgumentException e) { final Result result = Responses.newResult( ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED) .setDiagnosticMessage( ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(), dnString, e.getMessageObject()).toString()); throw ErrorResultException.wrap(result); } return subschemaDN; } static MatchingRule getDefaultMatchingRule() { return CoreSchema.getOctetStringMatchingRule(); } static Syntax getDefaultSyntax() { return CoreSchema.getOctetStringSyntax(); } private final Impl impl; private Schema(Impl impl) { this.impl = impl; } Schema(String schemaName, Map numericOID2Syntaxes, Map numericOID2MatchingRules, Map numericOID2MatchingRuleUses, Map numericOID2AttributeTypes, Map numericOID2ObjectClasses, Map numericOID2NameForms, Map numericOID2ContentRules, Map id2StructureRules, Map> name2MatchingRules, Map> name2MatchingRuleUses, Map> name2AttributeTypes, Map> name2ObjectClasses, Map> name2NameForms, Map> name2ContentRules, Map> name2StructureRules, Map> objectClass2NameForms, Map> nameForm2StructureRules, SchemaCompatOptions options, List warnings) { impl = new StrictImpl(schemaName, numericOID2Syntaxes, numericOID2MatchingRules, numericOID2MatchingRuleUses, numericOID2AttributeTypes, numericOID2ObjectClasses, numericOID2NameForms, numericOID2ContentRules, id2StructureRules, name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses, name2NameForms, name2ContentRules, name2StructureRules, objectClass2NameForms, nameForm2StructureRules, options, warnings); } /** * Returns the attribute type with the specified name or numeric OID. * * @param name * The name or OID of the attribute type to retrieve. * @return The requested attribute type. * @throws UnknownSchemaElementException * If this is a strict schema and the requested attribute * type was not found or if the provided name is ambiguous. */ public AttributeType getAttributeType(String name) throws UnknownSchemaElementException { return impl.getAttributeType(name); } /** * Returns an unmodifiable collection containing all of the attribute * types contained in this schema. * * @return An unmodifiable collection containing all of the attribute * types contained in this schema. */ public Collection getAttributeTypes() { return impl.getAttributeTypes(); } /** * Returns an unmodifiable collection containing all of the attribute * types having the specified name or numeric OID. * * @param name * The name or OID of the attribute types to retrieve. * @return An unmodifiable collection containing all of the attribute * types having the specified name or numeric OID. */ public List getAttributeTypesByName(String name) { return impl.getAttributeTypesByName(name); } /** * Returns the DIT content rule with the specified name or numeric * OID. * * @param name * The name or OID of the DIT content rule to retrieve. * @return The requested DIT content rule. * @throws UnknownSchemaElementException * If this is a strict schema and the requested DIT content * rule was not found or if the provided name is ambiguous. */ public DITContentRule getDITContentRule(String name) throws UnknownSchemaElementException { return impl.getDITContentRule(name); } /** * Returns an unmodifiable collection containing all of the DIT * content rules contained in this schema. * * @return An unmodifiable collection containing all of the DIT * content rules contained in this schema. */ public Collection getDITContentRules() { return impl.getDITContentRules(); } /** * Returns an unmodifiable collection containing all of the DIT * content rules having the specified name or numeric OID. * * @param name * The name or OID of the DIT content rules to retrieve. * @return An unmodifiable collection containing all of the DIT * content rules having the specified name or numeric OID. */ public Collection getDITContentRulesByName(String name) { return impl.getDITContentRulesByName(name); } /** * Returns the DIT structure rule with the specified name or numeric * OID. * * @param ruleID * The ID of the DIT structure rule to retrieve. * @return The requested DIT structure rule. * @throws UnknownSchemaElementException * If this is a strict schema and the requested DIT * structure rule was not found. */ public DITStructureRule getDITStructureRule(int ruleID) throws UnknownSchemaElementException { return impl.getDITStructureRule(ruleID); } /** * Returns an unmodifiable collection containing all of the DIT * structure rules having the specified name or numeric OID. * * @param name * The name or OID of the DIT structure rules to retrieve. * @return An unmodifiable collection containing all of the DIT * structure rules having the specified name or numeric OID. */ public Collection getDITStructureRulesByName( String name) { return impl.getDITStructureRulesByName(name); } /** * Retrieves the DIT structure rules for the provided name form. * * @param nameForm * The name form. * @return The requested DIT structure rules. */ public Collection getDITStructureRulesByNameForm( NameForm nameForm) { return impl.getDITStructureRulesByNameForm(nameForm); } /** * Returns an unmodifiable collection containing all of the DIT * structure rules contained in this schema. * * @return An unmodifiable collection containing all of the DIT * structure rules contained in this schema. */ public Collection getDITStuctureRules() { return impl.getDITStuctureRules(); } /** * Returns the matching rule with the specified name or numeric OID. * * @param name * The name or OID of the matching rule to retrieve. * @return The requested matching rule. * @throws UnknownSchemaElementException * If this is a strict schema and the requested matching * rule was not found or if the provided name is ambiguous. */ public MatchingRule getMatchingRule(String name) throws UnknownSchemaElementException { return impl.getMatchingRule(name); } /** * Returns an unmodifiable collection containing all of the matching * rules contained in this schema. * * @return An unmodifiable collection containing all of the matching * rules contained in this schema. */ public Collection getMatchingRules() { return impl.getMatchingRules(); } /** * Returns an unmodifiable collection containing all of the matching * rules having the specified name or numeric OID. * * @param name * The name or OID of the matching rules to retrieve. * @return An unmodifiable collection containing all of the matching * rules having the specified name or numeric OID. */ public Collection getMatchingRulesByName(String name) { return impl.getMatchingRulesByName(name); } /** * Returns the matching rule use associated with the provided matching * rule. * * @param matchingRule * The matching rule whose matching rule use is to be * retrieved. * @return The requested matching rule use. * @throws UnknownSchemaElementException * If this is a strict schema and the requested matching * rule use was not found or if the provided name is * ambiguous. */ public MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule) throws UnknownSchemaElementException { return getMatchingRuleUse(matchingRule.getOID()); } /** * Returns the matching rule use with the specified name or numeric * OID. * * @param name * The name or OID of the matching rule use to retrieve. * @return The requested matching rule use. * @throws UnknownSchemaElementException * If this is a strict schema and the requested matching * rule use was not found or if the provided name is * ambiguous. */ public MatchingRuleUse getMatchingRuleUse(String name) throws UnknownSchemaElementException { return impl.getMatchingRuleUse(name); } /** * Returns an unmodifiable collection containing all of the matching * rule uses contained in this schema. * * @return An unmodifiable collection containing all of the matching * rule uses contained in this schema. */ public Collection getMatchingRuleUses() { return impl.getMatchingRuleUses(); } /** * Returns an unmodifiable collection containing all of the matching * rule uses having the specified name or numeric OID. * * @param name * The name or OID of the matching rule uses to retrieve. * @return An unmodifiable collection containing all of the matching * rule uses having the specified name or numeric OID. */ public Collection getMatchingRuleUsesByName( String name) { return impl.getMatchingRuleUsesByName(name); } /** * Returns the name form with the specified name or numeric OID. * * @param name * The name or OID of the name form to retrieve. * @return The requested name form. * @throws UnknownSchemaElementException * If this is a strict schema and the requested name form * was not found or if the provided name is ambiguous. */ public NameForm getNameForm(String name) throws UnknownSchemaElementException { return impl.getNameForm(name); } /** * Retrieves the name forms for the specified structural objectclass. * * @param structuralClass * The structural objectclass for the name form to retrieve. * @return The requested name forms */ public Collection getNameFormByObjectClass( ObjectClass structuralClass) { return impl.getNameFormByObjectClass(structuralClass); } /** * Returns an unmodifiable collection containing all of the name forms * contained in this schema. * * @return An unmodifiable collection containing all of the name forms * contained in this schema. */ public Collection getNameForms() { return impl.getNameForms(); } /** * Returns an unmodifiable collection containing all of the name forms * having the specified name or numeric OID. * * @param name * The name or OID of the name forms to retrieve. * @return An unmodifiable collection containing all of the name forms * having the specified name or numeric OID. */ public Collection getNameFormsByName(String name) { return impl.getNameFormsByName(name); } /** * Returns the object class with the specified name or numeric OID. * * @param name * The name or OID of the object class to retrieve. * @return The requested object class. * @throws UnknownSchemaElementException * If this is a strict schema and the requested object class * was not found or if the provided name is ambiguous. */ public ObjectClass getObjectClass(String name) throws UnknownSchemaElementException { return impl.getObjectClass(name); } /** * Returns an unmodifiable collection containing all of the object * classes contained in this schema. * * @return An unmodifiable collection containing all of the object * classes contained in this schema. */ public Collection getObjectClasses() { return impl.getObjectClasses(); } /** * Returns an unmodifiable collection containing all of the object * classes having the specified name or numeric OID. * * @param name * The name or OID of the object classes to retrieve. * @return An unmodifiable collection containing all of the object * classes having the specified name or numeric OID. */ public Collection getObjectClassesByName(String name) { return impl.getObjectClassesByName(name); } /** * Returns the user-friendly name of this schema which may be used for * debugging purposes. The format of the schema name is not defined * but should contain the distinguished name of the subschema * sub-entry for those schemas retrieved from a Directory Server. * * @return The user-friendly name of this schema which may be used for * debugging purposes. */ public String getSchemaName() { return impl.getSchemaName(); } /** * Returns the syntax with the specified numeric OID. * * @param numericOID * The OID of the syntax to retrieve. * @return The requested syntax. * @throws UnknownSchemaElementException * If this is a strict schema and the requested syntax was * not found or if the provided name is ambiguous. */ public Syntax getSyntax(String numericOID) throws UnknownSchemaElementException { return impl.getSyntax(numericOID); } /** * Returns an unmodifiable collection containing all of the syntaxes * contained in this schema. * * @return An unmodifiable collection containing all of the syntaxes * contained in this schema. */ public Collection getSyntaxes() { return impl.getSyntaxes(); } /** * Returns an unmodifiable collection containing all of the warnings * that were detected when this schema was constructed. * * @return An unmodifiable collection containing all of the warnings * that were detected when this schema was constructed. */ public Collection getWarnings() { return impl.getWarnings(); } /** * Indicates whether or not this schema contains an attribute type * with the specified name or numeric OID. * * @param name * The name or OID of the attribute type. * @return {@code true} if this schema contains an attribute type with * the specified name or numeric OID, otherwise {@code false}. */ public boolean hasAttributeType(String name) { return impl.hasAttributeType(name); } /** * Indicates whether or not this schema contains a DIT content rule * with the specified name or numeric OID. * * @param name * The name or OID of the DIT content rule. * @return {@code true} if this schema contains a DIT content rule * with the specified name or numeric OID, otherwise {@code * false}. */ public boolean hasDITContentRule(String name) { return impl.hasDITContentRule(name); } /** * Indicates whether or not this schema contains a DIT structure rule * with the specified rule ID. * * @param ruleID * The ID of the DIT structure rule. * @return {@code true} if this schema contains a DIT structure rule * with the specified rule ID, otherwise {@code false}. */ public boolean hasDITStructureRule(int ruleID) { return impl.hasDITStructureRule(ruleID); } /** * Indicates whether or not this schema contains a matching rule with * the specified name or numeric OID. * * @param name * The name or OID of the matching rule. * @return {@code true} if this schema contains a matching rule with * the specified name or numeric OID, otherwise {@code false}. */ public boolean hasMatchingRule(String name) { return impl.hasMatchingRule(name); } /** * Indicates whether or not this schema contains a matching rule use * with the specified name or numeric OID. * * @param name * The name or OID of the matching rule use. * @return {@code true} if this schema contains a matching rule use * with the specified name or numeric OID, otherwise {@code * false}. */ public boolean hasMatchingRuleUse(String name) { return impl.hasMatchingRuleUse(name); } /** * Indicates whether or not this schema contains a name form with the * specified name or numeric OID. * * @param name * The name or OID of the name form. * @return {@code true} if this schema contains a name form with the * specified name or numeric OID, otherwise {@code false}. */ public boolean hasNameForm(String name) { return impl.hasNameForm(name); } /** * Indicates whether or not this schema contains an object class with * the specified name or numeric OID. * * @param name * The name or OID of the object class. * @return {@code true} if this schema contains an object class with * the specified name or numeric OID, otherwise {@code false}. */ public boolean hasObjectClass(String name) { return impl.hasObjectClass(name); } /** * Indicates whether or not this schema contains a syntax with the * specified numeric OID. * * @param numericOID * The OID of the syntax. * @return {@code true} if this schema contains a syntax with the * specified numeric OID, otherwise {@code false}. */ public boolean hasSyntax(String numericOID) { return impl.hasSyntax(numericOID); } /** * Indicates whether or not this schema is strict. Attribute type * queries in non-strict schema always succeed: if the requested * attribute type is not found then a temporary attribute type is * created automatically having the Octet String syntax and associated * matching rules. Strict schema, on the other hand, throw an * {@link UnknownSchemaElementException} whenever an attempt is made * to retrieve a non-existent attribute type. * * @return {@code true} if this schema is strict. */ public boolean isStrict() { return impl.isStrict(); } /** * Returns a non-strict view of this schema. Attribute type queries in * non-strict schema always succeed: if the requested attribute type * is not found then a temporary attribute type is created * automatically having the Octet String syntax and associated * matching rules. Strict schema, on the other hand, throw an * {@link UnknownSchemaElementException} whenever an attempt is made * to retrieve a non-existent attribute type. * * @return A non-strict view of this schema. */ public Schema nonStrict() { if (impl.isStrict()) { return new Schema(new NonStrictImpl(impl)); } else { return this; } } SchemaCompatOptions getSchemaCompatOptions() { return impl.getSchemaCompatOptions(); } }