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