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}.
*
* This method uses a Search operation to read the schema and does not perform
* caching. More specifically, it does not use the
* {@link Connection#readSchema} method.
*
* @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(final Connection connection, final 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}.
*
* This implementation first reads the {@code subschemaSubentry} attribute of
* the entry in order to identify the schema and then invokes
* {@link #readSchema} to read the schema. More specifically, it does not use
* the {@link AsynchronousConnection#readSchemaForEntry} method.
*
* @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,
final ResultHandler super Schema> handler)
throws UnsupportedOperationException, IllegalStateException,
NullPointerException
{
final RecursiveFutureResult future =
new RecursiveFutureResult(handler)
{
@Override
protected FutureResult chainResult(
final SearchResultEntry innerResult,
final ResultHandler super Schema> 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}.
*
* This implementation first reads the {@code subschemaSubentry} attribute of
* the entry in order to identify the schema and then invokes
* {@link #readSchema} to read the schema. More specifically, it does not use
* the {@link Connection#readSchemaForEntry} method.
*
* @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(final Connection connection,
final 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(final Schema schema)
{
defaultSchema = 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(final Entry entry)
{
return new SchemaBuilder(entry).toSchema();
}
static MatchingRule getDefaultMatchingRule()
{
return CoreSchema.getOctetStringMatchingRule();
}
static Syntax getDefaultSyntax()
{
return CoreSchema.getOctetStringSyntax();
}
// Constructs a search request for retrieving the subschemaSubentry
// attribute from the named entry.
private static SearchRequest getReadSchemaForEntrySearchRequest(final 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(final DN dn)
{
return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
}
private static DN getSubschemaSubentryDN(final 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;
}
private final Impl impl;
Schema(final String schemaName,
final Map numericOID2Syntaxes,
final Map numericOID2MatchingRules,
final Map numericOID2MatchingRuleUses,
final Map numericOID2AttributeTypes,
final Map numericOID2ObjectClasses,
final Map numericOID2NameForms,
final Map numericOID2ContentRules,
final Map id2StructureRules,
final Map> name2MatchingRules,
final Map> name2MatchingRuleUses,
final Map> name2AttributeTypes,
final Map> name2ObjectClasses,
final Map> name2NameForms,
final Map> name2ContentRules,
final Map> name2StructureRules,
final Map> objectClass2NameForms,
final Map> nameForm2StructureRules,
final SchemaCompatOptions options, final 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);
}
private Schema(final Impl impl)
{
this.impl = impl;
}
/**
* 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(final 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(final 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(final 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(final 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(final 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(
final 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(
final 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(final 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(final 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(final 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(final 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(final 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(final 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(
final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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;
}
}
/**
* Adds the definitions of all the schema elements contained in this schema to
* the provided subschema subentry. Any existing attributes (including schema
* definitions) contained in the provided entry will be preserved.
*
* @param entry
* The subschema subentry to which all schema definitions should be
* added.
* @return The updated subschema subentry.
* @throws NullPointerException
* If {@code entry} was {@code null}.
*/
public Entry toEntry(Entry entry) throws NullPointerException
{
Attribute attr = new LinkedAttribute(Schema.ATTR_LDAP_SYNTAXES);
for (Syntax syntax : getSyntaxes())
{
attr.add(syntax.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
for (AttributeType attributeType : getAttributeTypes())
{
attr.add(attributeType.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_OBJECT_CLASSES);
for (ObjectClass objectClass : getObjectClasses())
{
attr.add(objectClass.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULE_USE);
for (MatchingRuleUse matchingRuleUse : getMatchingRuleUses())
{
attr.add(matchingRuleUse.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULES);
for (MatchingRule matchingRule : getMatchingRules())
{
attr.add(matchingRule.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_DIT_CONTENT_RULES);
for (DITContentRule ditContentRule : getDITContentRules())
{
attr.add(ditContentRule.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
for (DITStructureRule ditStructureRule : getDITStuctureRules())
{
attr.add(ditStructureRule.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
attr = new LinkedAttribute(Schema.ATTR_NAME_FORMS);
for (NameForm nameForm : getNameForms())
{
attr.add(nameForm.toString());
}
if (!attr.isEmpty())
{
entry.addAttribute(attr);
}
return entry;
}
SchemaCompatOptions getSchemaCompatOptions()
{
return impl.getSchemaCompatOptions();
}
}