mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
07.20.2012 9898c1656694000aa090269e7b9889894cf2f063
Fix OPENDJ-484: Implement equals and hashCode for SDK schema elements
13 files modified
650 ■■■■■ changed files
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java 23 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java 27 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRule.java 27 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java 4 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java 136 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java 26 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUse.java 27 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java 27 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java 23 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java 102 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java 186 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaElement.java 15 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Syntax.java 27 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
@@ -228,18 +228,25 @@
        }
    }
    /**
     * Returns {@code true} if the provided object is an attribute type having
     * the same numeric OID as this attribute type.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is an attribute type having
     *         the same numeric OID as this attribute type.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof AttributeType) {
        } else if (o instanceof AttributeType) {
            final AttributeType other = (AttributeType) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
        return false;
    }
    /**
@@ -349,6 +356,12 @@
        return attributeUsage;
    }
    /**
     * Returns the hash code for this attribute type. It will be calculated as
     * the hash code of the numeric OID.
     *
     * @return The hash code for this attribute type.
     */
    @Override
    public int hashCode() {
        return oid.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
@@ -105,6 +105,27 @@
    }
    /**
     * Returns {@code true} if the provided object is a DIT content rule having
     * the same structural object class OID as this DIT content rule.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a DIT content rule having
     *         the same numeric OID as this DIT content rule.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        } else if (o instanceof DITContentRule) {
            final DITContentRule other = (DITContentRule) o;
            return structuralClassOID.equals(other.structuralClassOID);
        } else {
            return false;
        }
    }
    /**
     * Returns an unmodifiable set containing the auxiliary objectclasses that
     * may be used for entries associated with this DIT content rule.
     *
@@ -191,6 +212,12 @@
        return structuralClassOID;
    }
    /**
     * Returns the hash code for this DIT content rule. It will be calculated as
     * the hash code of the structural object class OID.
     *
     * @return The hash code for this DIT content rule.
     */
    @Override
    public int hashCode() {
        return structuralClassOID.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRule.java
@@ -93,6 +93,27 @@
    }
    /**
     * Returns {@code true} if the provided object is a DIT structure rule
     * having the same rule ID as this DIT structure rule.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a DIT structure rule
     *         having the same rule ID as this DIT structure rule.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        } else if (o instanceof DITStructureRule) {
            final DITStructureRule other = (DITStructureRule) o;
            return ruleID.equals(other.ruleID);
        } else {
            return false;
        }
    }
    /**
     * Retrieves the name form for this DIT structure rule.
     *
     * @return The name form for this DIT structure rule.
@@ -146,6 +167,12 @@
        return superiorRules;
    }
    /**
     * Returns the hash code for this DIT structure rule. It will be calculated
     * as the hash code of the rule ID.
     *
     * @return The hash code for this DIT structure rule.
     */
    @Override
    public int hashCode() {
        return ruleID.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java
@@ -32,9 +32,9 @@
 * can cause initialization errors because the CoreSchema depends on Schema.
 */
final class DefaultSchema {
    static volatile Schema schema = Schema.getCoreSchema();
    private DefaultSchema() {
        // Prevent instantiation.
    }
    static volatile Schema schema = Schema.getCoreSchema();
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -46,74 +46,6 @@
 */
final class DistinguishedNameEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl {
    /**
     * {@inheritDoc}
     */
    public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
            throws DecodeException {
        try {
            DN dn = DN.valueOf(value.toString(), schema.asNonStrictSchema());
            StringBuilder builder = new StringBuilder(value.length());
            return ByteString.valueOf(normalizeDN(builder, dn));
        } catch (final LocalizedIllegalArgumentException e) {
            throw DecodeException.error(e.getMessageObject());
        }
    }
    /**
     * Returns the normalized string representation of a DN.
     *
     * @param builder
     *            The StringBuilder to use to construct the normalized string.
     * @param dn
     *            The DN.
     * @return The normalized string representation of the provided DN.
     */
    private static StringBuilder normalizeDN(final StringBuilder builder, final DN dn) {
        if (dn.rdn() == null) {
            return builder;
        }
        int i = dn.size() - 1;
        normalizeRDN(builder, dn.parent(i).rdn());
        for (i--; i >= 0; i--) {
            builder.append('\u0000');
            normalizeRDN(builder, dn.parent(i).rdn());
        }
        return builder;
    }
    /**
     * Returns the normalized string representation of a RDN.
     *
     * @param builder
     *            The StringBuilder to use to construct the normalized string.
     * @param rdn
     *            The RDN.
     * @return The normalized string representation of the provided RDN.
     */
    private static StringBuilder normalizeRDN(final StringBuilder builder, final RDN rdn) {
        final int sz = rdn.size();
        if (sz == 1) {
            return normalizeAVA(builder, rdn.getFirstAVA());
        } else {
            // Need to sort the AVAs before comparing.
            TreeSet<AVA> a = new TreeSet<AVA>();
            for (AVA ava : rdn) {
                a.add(ava);
            }
            Iterator<AVA> i = a.iterator();
            // Normalize the first AVA.
            normalizeAVA(builder, i.next());
            while (i.hasNext()) {
                builder.append('\u0001');
                normalizeAVA(builder, i.next());
            }
            return builder;
        }
    }
    /**
     * Returns the normalized string representation of an AVA.
     *
     * @param builder
@@ -181,4 +113,72 @@
        }
        return builder;
    }
    /**
     * Returns the normalized string representation of a DN.
     *
     * @param builder
     *            The StringBuilder to use to construct the normalized string.
     * @param dn
     *            The DN.
     * @return The normalized string representation of the provided DN.
     */
    private static StringBuilder normalizeDN(final StringBuilder builder, final DN dn) {
        if (dn.rdn() == null) {
            return builder;
        }
        int i = dn.size() - 1;
        normalizeRDN(builder, dn.parent(i).rdn());
        for (i--; i >= 0; i--) {
            builder.append('\u0000');
            normalizeRDN(builder, dn.parent(i).rdn());
        }
        return builder;
    }
    /**
     * Returns the normalized string representation of a RDN.
     *
     * @param builder
     *            The StringBuilder to use to construct the normalized string.
     * @param rdn
     *            The RDN.
     * @return The normalized string representation of the provided RDN.
     */
    private static StringBuilder normalizeRDN(final StringBuilder builder, final RDN rdn) {
        final int sz = rdn.size();
        if (sz == 1) {
            return normalizeAVA(builder, rdn.getFirstAVA());
        } else {
            // Need to sort the AVAs before comparing.
            TreeSet<AVA> a = new TreeSet<AVA>();
            for (AVA ava : rdn) {
                a.add(ava);
            }
            Iterator<AVA> i = a.iterator();
            // Normalize the first AVA.
            normalizeAVA(builder, i.next());
            while (i.hasNext()) {
                builder.append('\u0001');
                normalizeAVA(builder, i.next());
            }
            return builder;
        }
    }
    /**
     * {@inheritDoc}
     */
    public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
            throws DecodeException {
        try {
            DN dn = DN.valueOf(value.toString(), schema.asNonStrictSchema());
            StringBuilder builder = new StringBuilder(value.length());
            return ByteString.valueOf(normalizeDN(builder, dn));
        } catch (final LocalizedIllegalArgumentException e) {
            throw DecodeException.error(e.getMessageObject());
        }
    }
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
@@ -100,23 +100,24 @@
    }
    /**
     * {@inheritDoc}
     * Returns {@code true} if the provided object is a matching rule having the
     * same numeric OID as this matching rule.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a matching rule having the
     *         same numeric OID as this matching rule.
     */
    @Override
    public boolean equals(final Object o) {
        if (o == null) {
            return false;
        }
        if (this == o) {
            return true;
        }
        if (!(o instanceof MatchingRule)) {
        } else if (o instanceof MatchingRule) {
            final MatchingRule other = (MatchingRule) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
        return getOID().equals(((MatchingRule) o).getOID());
    }
    /**
@@ -238,7 +239,10 @@
    }
    /**
     * {@inheritDoc}
     * Returns the hash code for this matching rule. It will be calculated as
     * the hash code of the numeric OID.
     *
     * @return The hash code for this matching rule.
     */
    @Override
    public int hashCode() {
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUse.java
@@ -85,6 +85,27 @@
    }
    /**
     * Returns {@code true} if the provided object is a matching rule use having
     * the same numeric OID as this matching rule use.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a matching rule use having
     *         the same numeric OID as this matching rule use.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        } else if (o instanceof MatchingRuleUse) {
            final MatchingRuleUse other = (MatchingRuleUse) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
    }
    /**
     * Returns an unmodifiable set containing the attributes associated with
     * this matching rule use.
     *
@@ -151,6 +172,12 @@
        return attributes.contains(attributeType);
    }
    /**
     * Returns the hash code for this matching rule use. It will be calculated
     * as the hash code of the numeric OID.
     *
     * @return The hash code for this matching rule use.
     */
    @Override
    public int hashCode() {
        return oid.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
@@ -98,6 +98,27 @@
    }
    /**
     * Returns {@code true} if the provided object is a name form having the
     * same numeric OID as this name form.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a name form having the
     *         same numeric OID as this name form.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        } else if (o instanceof NameForm) {
            final NameForm other = (NameForm) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
    }
    /**
     * Returns the name or OID for this schema definition. If it has one or more
     * names, then the primary name will be returned. If it does not have any
     * names, then the OID will be returned.
@@ -163,6 +184,12 @@
        return structuralClass;
    }
    /**
     * Returns the hash code for this name form. It will be calculated as the
     * hash code of the numeric OID.
     *
     * @return The hash code for this name form.
     */
    @Override
    public int hashCode() {
        return oid.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
@@ -136,18 +136,25 @@
        this.definition = buildDefinition();
    }
    /**
     * Returns {@code true} if the provided object is an object class having the
     * same numeric OID as this object class.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is a object class having the
     *         same numeric OID as this object class.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof ObjectClass) {
        } else if (o instanceof ObjectClass) {
            final ObjectClass other = (ObjectClass) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
        return false;
    }
    /**
@@ -252,6 +259,12 @@
        return superiorClasses;
    }
    /**
     * Returns the hash code for this object class. It will be calculated as the
     * hash code of the numeric OID.
     *
     * @return The hash code for this object class.
     */
    @Override
    public int hashCode() {
        return oid.hashCode();
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -299,6 +299,12 @@
    }
    private static interface Impl {
        boolean allowMalformedNamesAndOptions();
        boolean allowNonStandardTelephoneNumbers();
        boolean allowZeroLengthDirectoryStrings();
        AttributeType getAttributeType(String name);
        Collection<AttributeType> getAttributeTypes();
@@ -374,12 +380,6 @@
        boolean hasSyntax(String numericOID);
        boolean isStrict();
        boolean allowMalformedNamesAndOptions();
        boolean allowNonStandardTelephoneNumbers();
        boolean allowZeroLengthDirectoryStrings();
    }
    private static final class NonStrictImpl implements Impl {
@@ -1124,6 +1124,35 @@
    }
    /**
     * Reads the schema contained in the named subschema sub-entry.
     * <p>
     * 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 UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.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 {
        return new SchemaBuilder().addSchema(connection, name, true).toSchema();
    }
    /**
     * Asynchronously reads the schema contained in the named subschema
     * sub-entry.
     * <p>
@@ -1169,18 +1198,26 @@
    }
    /**
     * Reads the schema contained in the named subschema sub-entry.
     * Reads the schema contained in the subschema sub-entry which applies to
     * the named entry.
     * <p>
     * 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}.
     * 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}.
     * <p>
     * This implementation first reads the {@code subschemaSubentry} attribute
     * of the entry in order to identify the schema and then invokes
     * {@link #readSchema(Connection, DN)} to read the schema.
     *
     * @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.
     *            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.
@@ -1192,9 +1229,9 @@
     * @throws NullPointerException
     *             If the {@code connection} or {@code name} was {@code null}.
     */
    public static Schema readSchema(final Connection connection, final DN name)
    public static Schema readSchemaForEntry(final Connection connection, final DN name)
            throws ErrorResultException {
        return new SchemaBuilder().addSchema(connection, name, true).toSchema();
        return new SchemaBuilder().addSchemaForEntry(connection, name, true).toSchema();
    }
    /**
@@ -1251,43 +1288,6 @@
    }
    /**
     * Reads the schema contained in the subschema sub-entry which applies to
     * the named entry.
     * <p>
     * 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}.
     * <p>
     * This implementation first reads the {@code subschemaSubentry} attribute
     * of the entry in order to identify the schema and then invokes
     * {@link #readSchema(Connection, DN)} to read the schema.
     *
     * @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 UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.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 {
        return new SchemaBuilder().addSchemaForEntry(connection, name, true).toSchema();
    }
    /**
     * Sets the default schema which should be used by this application. The
     * default schema is initially set to the core schema.
     *
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -96,7 +96,7 @@
    // attribute from the named entry.
    private static SearchRequest getReadSchemaForEntrySearchRequest(final DN dn) {
        return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter
                .getObjectClassPresentFilter(), SUBSCHEMA_SUBENTRY_ATTRS);
                .objectClassPresent(), SUBSCHEMA_SUBENTRY_ATTRS);
    }
    // Constructs a search request for retrieving the named subschema
@@ -1711,56 +1711,6 @@
    }
    /**
     * Asynchronously reads the schema elements contained in the named subschema
     * sub-entry and adds them to this schema builder.
     * <p>
     * If the requested schema is not returned by the Directory Server then the
     * request will fail with an {@link EntryNotFoundException}.
     *
     * @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}.
     * @param overwrite
     *            {@code true} if existing schema elements with the same
     *            conflicting OIDs should be overwritten.
     * @return A future representing the updated schema builder.
     * @throws UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.isClosed() == true}.
     * @throws NullPointerException
     *             If the {@code connection} or {@code name} was {@code null}.
     */
    public FutureResult<SchemaBuilder> addSchemaAsync(final Connection connection, final DN name,
            final ResultHandler<? super SchemaBuilder> handler, final boolean overwrite) {
        // The call to addSchema will perform copyOnWrite.
        final SearchRequest request = getReadSchemaSearchRequest(name);
        final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
                new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler) {
                    @Override
                    protected SchemaBuilder transformResult(final SearchResultEntry result)
                            throws ErrorResultException {
                        addSchema(result, overwrite);
                        return SchemaBuilder.this;
                    }
                };
        final FutureResult<SearchResultEntry> innerFuture =
                connection.searchSingleEntryAsync(request, future);
        future.setFutureResult(innerFuture);
        return future;
    }
    /**
     * Reads the schema elements contained in the named subschema sub-entry and
     * adds them to this schema builder.
     * <p>
@@ -1932,6 +1882,98 @@
    }
    /**
     * Asynchronously reads the schema elements contained in the named subschema
     * sub-entry and adds them to this schema builder.
     * <p>
     * If the requested schema is not returned by the Directory Server then the
     * request will fail with an {@link EntryNotFoundException}.
     *
     * @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}.
     * @param overwrite
     *            {@code true} if existing schema elements with the same
     *            conflicting OIDs should be overwritten.
     * @return A future representing the updated schema builder.
     * @throws UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.isClosed() == true}.
     * @throws NullPointerException
     *             If the {@code connection} or {@code name} was {@code null}.
     */
    public FutureResult<SchemaBuilder> addSchemaAsync(final Connection connection, final DN name,
            final ResultHandler<? super SchemaBuilder> handler, final boolean overwrite) {
        // The call to addSchema will perform copyOnWrite.
        final SearchRequest request = getReadSchemaSearchRequest(name);
        final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
                new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler) {
                    @Override
                    protected SchemaBuilder transformResult(final SearchResultEntry result)
                            throws ErrorResultException {
                        addSchema(result, overwrite);
                        return SchemaBuilder.this;
                    }
                };
        final FutureResult<SearchResultEntry> innerFuture =
                connection.searchSingleEntryAsync(request, future);
        future.setFutureResult(innerFuture);
        return future;
    }
    /**
     * Reads the schema elements contained in the subschema sub-entry which
     * applies to the named entry and adds them to this schema builder.
     * <p>
     * If the requested entry or its associated schema are not returned by the
     * Directory Server then the request will fail with an
     * {@link EntryNotFoundException}.
     * <p>
     * This implementation first reads the {@code subschemaSubentry} attribute
     * of the entry in order to identify the schema and then invokes
     * {@link #addSchemaForEntry(Connection, DN, boolean)} to read the schema.
     *
     * @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 overwrite
     *            {@code true} if existing schema elements with the same
     *            conflicting OIDs should be overwritten.
     * @return A reference to this schema builder.
     * @throws ErrorResultException
     *             If the result code indicates that the request failed for some
     *             reason.
     * @throws UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.isClosed() == true}.
     * @throws NullPointerException
     *             If the {@code connection} or {@code name} was {@code null}.
     */
    public SchemaBuilder addSchemaForEntry(final Connection connection, final DN name,
            final boolean overwrite) throws ErrorResultException {
        // The call to addSchema will perform copyOnWrite.
        final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
        final Entry entry = connection.searchSingleEntry(request);
        final DN subschemaDN = getSubschemaSubentryDN(name, entry);
        return addSchema(connection, subschemaDN, overwrite);
    }
    /**
     * Asynchronously reads the schema elements contained in the subschema
     * sub-entry which applies to the named entry and adds them to this schema
     * builder.
@@ -1992,48 +2034,6 @@
    }
    /**
     * Reads the schema elements contained in the subschema sub-entry which
     * applies to the named entry and adds them to this schema builder.
     * <p>
     * If the requested entry or its associated schema are not returned by the
     * Directory Server then the request will fail with an
     * {@link EntryNotFoundException}.
     * <p>
     * This implementation first reads the {@code subschemaSubentry} attribute
     * of the entry in order to identify the schema and then invokes
     * {@link #addSchemaForEntry(Connection, DN, boolean)} to read the schema.
     *
     * @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 overwrite
     *            {@code true} if existing schema elements with the same
     *            conflicting OIDs should be overwritten.
     * @return A reference to this schema builder.
     * @throws ErrorResultException
     *             If the result code indicates that the request failed for some
     *             reason.
     * @throws UnsupportedOperationException
     *             If the connection does not support search operations.
     * @throws IllegalStateException
     *             If the connection has already been closed, i.e. if
     *             {@code connection.isClosed() == true}.
     * @throws NullPointerException
     *             If the {@code connection} or {@code name} was {@code null}.
     */
    public SchemaBuilder addSchemaForEntry(final Connection connection, final DN name,
            final boolean overwrite) throws ErrorResultException {
        // The call to addSchema will perform copyOnWrite.
        final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
        final Entry entry = connection.searchSingleEntry(request);
        final DN subschemaDN = getSubschemaSubentryDN(name, entry);
        return addSchema(connection, subschemaDN, overwrite);
    }
    /**
     * Adds the provided substitution syntax definition to this schema builder.
     *
     * @param oid
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaElement.java
@@ -58,6 +58,11 @@
    }
    /**
     * {@inheritDoc}
     */
    public abstract boolean equals(Object obj);
    /**
     * Returns the description of this schema definition.
     *
     * @return The description of this schema definition.
@@ -97,6 +102,16 @@
    }
    /**
     * {@inheritDoc}
     */
    public abstract int hashCode();
    /**
     * {@inheritDoc}
     */
    public abstract String toString();
    /**
     * Builds a string representation of this schema definition in the form
     * specified in RFC 2252.
     *
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Syntax.java
@@ -90,6 +90,27 @@
    }
    /**
     * Returns {@code true} if the provided object is an attribute syntax having
     * the same numeric OID as this attribute syntax.
     *
     * @param o
     *            The object to be compared.
     * @return {@code true} if the provided object is an attribute syntax having
     *         the same numeric OID as this attribute syntax.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        } else if (o instanceof Syntax) {
            final Syntax other = (Syntax) o;
            return oid.equals(other.oid);
        } else {
            return false;
        }
    }
    /**
     * Retrieves the default approximate matching rule that will be used for
     * attributes with this syntax.
     *
@@ -147,14 +168,14 @@
    }
    /**
     * Retrieves the hash code for this schema element. It will be calculated as
     * the sum of the characters in the OID.
     * Returns the hash code for this attribute syntax. It will be calculated as
     * the hash code of the numeric OID.
     *
     * @return The hash code for this attribute syntax.
     */
    @Override
    public int hashCode() {
        return getOID().hashCode();
        return oid.hashCode();
    }
    /**