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 *     http://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.parsers;
021
022
023import java.util.List;
024
025import org.apache.directory.api.ldap.model.schema.AttributeType;
026import org.apache.directory.api.ldap.model.schema.LdapSyntax;
027import org.apache.directory.api.ldap.model.schema.MatchingRule;
028import org.apache.directory.api.ldap.model.schema.ObjectClass;
029import org.apache.directory.api.ldap.model.schema.SchemaObject;
030
031
032/**
033 * Utilities for dealing with various schema descriptions.
034 *
035 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
036 */
037public final class ParserDescriptionUtils
038{
039    /**
040     * Private constructor.
041     */
042    private ParserDescriptionUtils()
043    {
044    }
045
046
047    /**
048     * Checks two schema objectClasses for an exact match.
049     *
050     * @param oc0 the first objectClass to compare
051     * @param oc1 the second objectClass to compare
052     * @return true if both objectClasses match exactly, false otherwise
053     */
054    public static boolean objectClassesMatch( ObjectClass oc0, ObjectClass oc1 )
055    {
056        // compare all common description parameters
057        if ( !descriptionsMatch( oc0, oc1 ) )
058        {
059            return false;
060        }
061
062        // compare the objectClass type (AUXILIARY, STRUCTURAL, ABSTRACT)
063        if ( oc0.getType() != oc1.getType() )
064        {
065            return false;
066        }
067
068        // compare the superior objectClasses (sizes must match)
069        if ( oc0.getSuperiorOids().size() != oc1.getSuperiorOids().size() )
070        {
071            return false;
072        }
073
074        // compare the superior objectClasses (sizes must match)
075        for ( int i = 0; i < oc0.getSuperiorOids().size(); i++ )
076        {
077            if ( !oc0.getSuperiorOids().get( i ).equals( oc1.getSuperiorOids().get( i ) ) )
078            {
079                return false;
080            }
081        }
082
083        // compare the must attributes (sizes must match)
084        for ( int i = 0; i < oc0.getMustAttributeTypeOids().size(); i++ )
085        {
086            if ( !oc0.getMustAttributeTypeOids().get( i ).equals( oc1.getMustAttributeTypeOids().get( i ) ) )
087            {
088                return false;
089            }
090        }
091
092        // compare the may attributes (sizes must match)
093        for ( int i = 0; i < oc0.getMayAttributeTypeOids().size(); i++ )
094        {
095            if ( !oc0.getMayAttributeTypeOids().get( i ).equals( oc1.getMayAttributeTypeOids().get( i ) ) )
096            {
097                return false;
098            }
099        }
100
101        return true;
102    }
103
104
105    /**
106     * Checks two schema attributeTypes for an exact match.
107     *
108     * @param at0 the first attributeType to compare
109     * @param at1 the second attributeType to compare
110     * @return true if both attributeTypes match exactly, false otherwise
111     */
112    public static boolean attributeTypesMatch( AttributeType at0, AttributeType at1 )
113    {
114        // compare all common description parameters
115        if ( !descriptionsMatch( at0, at1 ) )
116        {
117            return false;
118        }
119
120        // check that the same super type is being used for both attributes
121        if ( !at0.getSuperiorOid().equals( at1.getSuperiorOid() ) )
122        {
123            return false;
124        }
125
126        // check that the same matchingRule is used by both ATs for EQUALITY
127        if ( !at0.getEqualityOid().equals( at1.getEqualityOid() ) )
128        {
129            return false;
130        }
131
132        // check that the same matchingRule is used by both ATs for SUBSTRING
133        if ( !at0.getSubstringOid().equals( at1.getSubstringOid() ) )
134        {
135            return false;
136        }
137
138        // check that the same matchingRule is used by both ATs for ORDERING
139        if ( !at0.getOrderingOid().equals( at1.getOrderingOid() ) )
140        {
141            return false;
142        }
143
144        // check that the same syntax is used by both ATs
145        if ( !at0.getSyntaxOid().equals( at1.getSyntaxOid() ) )
146        {
147            return false;
148        }
149
150        // check that the syntax length constraint is the same for both
151        if ( at0.getSyntaxLength() != at1.getSyntaxLength() )
152        {
153            return false;
154        }
155
156        // check that the ATs have the same single valued flag value
157        if ( at0.isSingleValued() != at1.isSingleValued() )
158        {
159            return false;
160        }
161
162        // check that the ATs have the same collective flag value
163        if ( at0.isCollective() != at1.isCollective() )
164        {
165            return false;
166        }
167
168        // check that the ATs have the same user modifiable flag value
169        if ( at0.isUserModifiable() != at1.isUserModifiable() )
170        {
171            return false;
172        }
173
174        // check that the ATs have the same USAGE
175        if ( at0.getUsage() != at1.getUsage() )
176        {
177            return false;
178        }
179
180        return true;
181    }
182
183
184    /**
185     * Checks to see if two matchingRule match exactly.
186     *
187     * @param matchingRule0 the first matchingRule to compare
188     * @param matchingRule1 the second matchingRule to compare
189     * @return true if the matchingRules match exactly, false otherwise
190     */
191    public static boolean matchingRulesMatch( MatchingRule matchingRule0, MatchingRule matchingRule1 )
192    {
193        // compare all common description parameters
194        if ( !descriptionsMatch( matchingRule0, matchingRule1 ) )
195        {
196            return false;
197        }
198
199        // check that the syntaxes of the matchingRules match
200        if ( !matchingRule0.getSyntaxOid().equals( matchingRule1.getSyntaxOid() ) )
201        {
202            return false;
203        }
204
205        return true;
206    }
207
208
209    /**
210     * Checks to see if two syntax match exactly.
211     *
212     * @param ldapSyntax0 the first ldapSyntax to compare
213     * @param ldapSyntax1 the second ldapSyntax to compare
214     * @return true if the syntaxes match exactly, false otherwise
215     */
216    public static boolean syntaxesMatch( LdapSyntax ldapSyntax0, LdapSyntax ldapSyntax1 )
217    {
218        return descriptionsMatch( ldapSyntax0, ldapSyntax1 );
219    }
220
221
222    /**
223     * Checks if two base schema descriptions match for the common components 
224     * in every schema description.  NOTE: for syntaxes the obsolete flag is 
225     * not compared because doing so would raise an exception since syntax 
226     * descriptions do not support the OBSOLETE flag.
227     * 
228     * @param so0 the first schema description to compare 
229     * @param so1 the second schema description to compare 
230     * @return true if the descriptions match exactly, false otherwise
231     */
232    public static boolean descriptionsMatch( SchemaObject so0, SchemaObject so1 )
233    {
234        // check that the OID matches
235        if ( !so0.getOid().equals( so1.getOid() ) )
236        {
237            return false;
238        }
239
240        // check that the obsolete flag is equal but not for syntaxes
241        if ( ( ( so0 instanceof LdapSyntax ) || ( so1 instanceof LdapSyntax ) ) && so0.isObsolete() != so1.isObsolete() )
242        {
243            return false;
244        }
245
246        // check that the description matches
247        if ( !so0.getDescription().equals( so1.getDescription() ) )
248        {
249            return false;
250        }
251
252        // check alias names for exact match
253        if ( !aliasNamesMatch( so0, so1 ) )
254        {
255            return false;
256        }
257
258        // check extensions for exact match
259        if ( !extensionsMatch( so0, so1 ) )
260        {
261            return false;
262        }
263
264        return true;
265    }
266
267
268    /**
269     * Checks to see if the extensions of a schema description match another
270     * description.  The order of the extension values must match for a true
271     * return.
272     *
273     * @param lsd0 the first schema description to compare the extensions of
274     * @param lsd1 the second schema description to compare the extensions of
275     * @return true if the extensions match exactly, false otherwise
276     */
277    public static boolean extensionsMatch( SchemaObject lsd0, SchemaObject lsd1 )
278    {
279        // check sizes first
280        if ( lsd0.getExtensions().size() != lsd1.getExtensions().size() )
281        {
282            return false;
283        }
284
285        // check contents and order of extension values must match
286        for ( String key : lsd0.getExtensions().keySet() )
287        {
288            List<String> values0 = lsd0.getExtension( key );
289            List<String> values1 = lsd1.getExtension( key );
290
291            // if the key is not present in asd1
292            if ( values1 == null )
293            {
294                return false;
295            }
296
297            for ( int i = 0; i < values0.size(); i++ )
298            {
299                if ( !values0.get( i ).equals( values1.get( i ) ) )
300                {
301                    return false;
302                }
303            }
304        }
305
306        return true;
307    }
308
309
310    /**
311     * Checks to see if the alias names of a schema description match another 
312     * description.  The order of the alias names do matter.
313     *
314     * @param so0 the schema description to compare
315     * @param so1 the schema description to compare
316     * @return true if alias names match exactly, false otherwise
317     */
318    public static boolean aliasNamesMatch( SchemaObject so0, SchemaObject so1 )
319    {
320        // check sizes first
321        if ( so0.getNames().size() != so1.getNames().size() )
322        {
323            return false;
324        }
325
326        // check contents and order must match too
327        for ( int i = 0; i < so0.getNames().size(); i++ )
328        {
329            if ( !so0.getNames().get( i ).equals( so1.getNames().get( i ) ) )
330            {
331                return false;
332            }
333        }
334
335        return true;
336    }
337}