001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    https://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.api.ldap.model.schema.comparators;
021
022
023import org.apache.directory.api.i18n.I18n;
024import org.apache.directory.api.ldap.model.constants.SchemaConstants;
025import org.apache.directory.api.ldap.model.exception.LdapException;
026import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
027import org.apache.directory.api.ldap.model.name.Dn;
028import org.apache.directory.api.ldap.model.schema.LdapComparator;
029import org.apache.directory.api.ldap.model.schema.SchemaManager;
030
031
032/**
033 * A comparator that sorts OIDs based on their numeric id value.  Needs a 
034 * OidRegistry to properly do it's job.  Public method to set the oid 
035 * registry will be used by the server after instantiation in deserialization.
036 *
037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038 */
039public class UniqueMemberComparator extends LdapComparator<String>
040{
041    /** The serial version UID */
042    private static final long serialVersionUID = 2L;
043
044    /** A reference to the schema manager */
045    private transient SchemaManager schemaManager;
046    
047    private transient ParsedDnComparator dnComparator = new ParsedDnComparator( SchemaConstants.ENTRY_DN_AT_OID );
048
049
050    /**
051     * The IntegerComparator constructor. Its OID is the IntegerOrderingMatch matching
052     * rule OID.
053     * 
054     * @param oid The Comparator's OID
055     */
056    public UniqueMemberComparator( String oid )
057    {
058        super( oid );
059    }
060
061
062    /**
063     * {@inheritDoc}
064     */
065    public int compare( String dnstr1, String dnstr2 )
066    {
067        int dash1 = dnstr1.lastIndexOf( '#' );
068        int dash2 = dnstr2.lastIndexOf( '#' );
069
070        if ( ( dash1 == -1 ) && ( dash2 == -1 ) )
071        {
072            // no UID part
073            try
074            {
075                Dn dn1 = getDn( dnstr1 );
076                Dn dn2 = getDn( dnstr2 );
077
078                return dnComparator.compare( dn1, dn2 );
079            }
080            catch ( LdapInvalidDnException ne )
081            {
082                return -1;
083            }
084        }
085        else
086        {
087            // Now, check that we don't have another '#'
088            if ( dnstr1.indexOf( '#' ) != dash1 )
089            {
090                // Yes, we have one : this is not allowed, it should have been
091                // escaped.
092                return -1;
093            }
094
095            if ( dnstr2.indexOf( '#' ) != dash1 )
096            {
097                // Yes, we have one : this is not allowed, it should have been
098                // escaped.
099                return 1;
100            }
101
102            Dn dn1;
103            Dn dn2;
104
105            // This is an UID if the '#' is immediatly
106            // followed by a BitString, except if the '#' is
107            // on the last position
108            String uid1 = dnstr1.substring( dash1 + 1 );
109
110            if ( dash1 > 0 )
111            {
112                try
113                {
114                    dn1 = new Dn( dnstr1.substring( 0, dash1 ) );
115                }
116                catch ( LdapException ne )
117                {
118                    return -1;
119                }
120            }
121            else
122            {
123                return -1;
124            }
125
126            // This is an UID if the '#' is immediately
127            // followed by a BitString, except if the '#' is
128            // on the last position
129            String uid2 = dnstr2.substring( dash2 + 1 );
130
131            if ( dash2 > 0 )
132            {
133                try
134                {
135                    dn2 = new Dn( dnstr1.substring( 0, dash2 ) );
136                }
137                catch ( LdapException ne )
138                {
139                    return 1;
140                }
141            }
142            else
143            {
144                return 1;
145            }
146
147            int dnResult = dnComparator.compare( dn1, dn2 );
148            
149            if ( dnResult == 0 )
150            {
151                return uid1.compareTo( uid2 );
152            }
153
154            return dnResult;
155        }
156    }
157
158
159    /**
160     * {@inheritDoc}
161     */
162    @Override
163    public void setSchemaManager( SchemaManager schemaManager )
164    {
165        this.schemaManager = schemaManager;
166    }
167
168
169    /**
170     * Get the DN from the given object
171     *
172     * @param obj The object containing a DN (either as an instance of Dn or as a String)
173     * @return A Dn instance
174     * @throws LdapInvalidDnException If the Dn is invalid
175     */
176    public Dn getDn( Object obj ) throws LdapInvalidDnException
177    {
178        Dn dn;
179
180        if ( obj instanceof Dn )
181        {
182            dn = ( Dn ) obj;
183
184            dn = dn.isSchemaAware() ? dn : new Dn( schemaManager, dn );
185        }
186        else if ( obj instanceof String )
187        {
188            dn = new Dn( schemaManager, ( String ) obj );
189        }
190        else
191        {
192            throw new IllegalStateException( I18n.err( I18n.ERR_13720_CANNOT_HANDLE_DN_COMPARISONS, obj == null ? null : obj.getClass() ) );
193        }
194
195        return dn;
196    }
197}