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.server.schema.registries;
021    
022    
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Properties;
029    
030    import org.apache.directory.server.schema.bootstrap.Schema;
031    import org.apache.directory.shared.ldap.schema.AttributeType;
032    import org.apache.directory.shared.ldap.schema.MatchingRule;
033    import org.apache.directory.shared.ldap.schema.ObjectClass;
034    import org.apache.directory.shared.ldap.schema.SchemaObject;
035    import org.apache.directory.shared.ldap.schema.Syntax;
036    
037    
038    /**
039     * A set of boostrap registries used to fire up the server.
040     *
041     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042     * @version $Rev: 778529 $
043     */
044    public class DefaultRegistries implements Registries
045    {
046        /** The AttributeType registry */
047        private AttributeTypeRegistry attributeTypeRegistry;
048        
049        /** The ObjectClass registry */
050        private DefaultObjectClassRegistry objectClassRegistry;
051    
052        private DefaultComparatorRegistry comparatorRegistry;
053        private DefaultDitContentRuleRegistry ditContentRuleRegistry;
054        private DefaultDitStructureRuleRegistry ditStructureRuleRegistry;
055        private DefaultMatchingRuleRegistry matchingRuleRegistry;
056        private DefaultMatchingRuleUseRegistry matchingRuleUseRegistry;
057        private DefaultNameFormRegistry nameFormRegistry;
058        private DefaultNormalizerRegistry normalizerRegistry;
059        private OidRegistry oidRegistry;
060        private DefaultSyntaxCheckerRegistry syntaxCheckerRegistry;
061        private DefaultSyntaxRegistry syntaxRegistry;
062        private Map<String,Schema> loadedByName = new HashMap<String, Schema>();
063        private final SchemaLoader schemaLoader;
064        private final String name;
065    
066    
067        public DefaultRegistries( String name, SchemaLoader schemaLoader, OidRegistry registry )
068        {
069            this.name = name;
070            this.schemaLoader = schemaLoader;
071            
072            this.schemaLoader.setListener( new SchemaLoaderListener() {
073                public void schemaLoaded( Schema schema )
074                {
075                    loadedByName.put( schema.getSchemaName(), schema );
076                }
077            });
078            
079            oidRegistry = registry;
080            normalizerRegistry = new DefaultNormalizerRegistry();
081            comparatorRegistry = new DefaultComparatorRegistry();
082            syntaxCheckerRegistry = new DefaultSyntaxCheckerRegistry();
083            syntaxRegistry = new DefaultSyntaxRegistry( oidRegistry );
084            matchingRuleRegistry = new DefaultMatchingRuleRegistry( oidRegistry );
085            attributeTypeRegistry = new DefaultAttributeTypeRegistry( oidRegistry );
086            objectClassRegistry = new DefaultObjectClassRegistry( oidRegistry );
087            ditContentRuleRegistry = new DefaultDitContentRuleRegistry( oidRegistry );
088            ditStructureRuleRegistry = new DefaultDitStructureRuleRegistry( oidRegistry );
089            matchingRuleUseRegistry = new DefaultMatchingRuleUseRegistry();
090            nameFormRegistry = new DefaultNameFormRegistry( oidRegistry );
091        }
092    
093    
094        public String getName()
095        {
096            return name;
097        }
098        
099        
100        public AttributeTypeRegistry getAttributeTypeRegistry()
101        {
102            return attributeTypeRegistry;
103        }
104    
105    
106        public ComparatorRegistry getComparatorRegistry()
107        {
108            return comparatorRegistry;
109        }
110    
111    
112        public DITContentRuleRegistry getDitContentRuleRegistry()
113        {
114            return ditContentRuleRegistry;
115        }
116    
117    
118        public DITStructureRuleRegistry getDitStructureRuleRegistry()
119        {
120            return ditStructureRuleRegistry;
121        }
122    
123    
124        public MatchingRuleRegistry getMatchingRuleRegistry()
125        {
126            return matchingRuleRegistry;
127        }
128    
129    
130        public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
131        {
132            return matchingRuleUseRegistry;
133        }
134    
135    
136        public NameFormRegistry getNameFormRegistry()
137        {
138            return nameFormRegistry;
139        }
140    
141    
142        public NormalizerRegistry getNormalizerRegistry()
143        {
144            return normalizerRegistry;
145        }
146    
147    
148        public ObjectClassRegistry getObjectClassRegistry()
149        {
150            return objectClassRegistry;
151        }
152    
153    
154        public OidRegistry getOidRegistry()
155        {
156            return oidRegistry;
157        }
158    
159    
160        public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
161        {
162            return syntaxCheckerRegistry;
163        }
164    
165    
166        public SyntaxRegistry getSyntaxRegistry()
167        {
168            return syntaxRegistry;
169        }
170    
171    
172        // ------------------------------------------------------------------------
173        // Code used to sanity check the resolution of entities in registries
174        // ------------------------------------------------------------------------
175    
176        /**
177         * Attempts to resolve the dependent schema objects of all entities that
178         * refer to other objects within the registries.  Null references will be
179         * handed appropriately.
180         *
181         * @return a list of exceptions encountered while resolving entities
182         */
183        public List<Throwable> checkRefInteg()
184        {
185            ArrayList<Throwable> errors = new ArrayList<Throwable>();
186    
187            Iterator<?> list = objectClassRegistry.iterator();
188            while ( list.hasNext() )
189            {
190                ObjectClass oc = ( ObjectClass ) list.next();
191                resolve( oc, errors );
192            }
193    
194            list = attributeTypeRegistry.iterator();
195            while ( list.hasNext() )
196            {
197                AttributeType at = ( AttributeType ) list.next();
198                resolve( at, errors );
199            }
200    
201            list = matchingRuleRegistry.iterator();
202            while ( list.hasNext() )
203            {
204                MatchingRule mr = ( MatchingRule ) list.next();
205                resolve( mr, errors );
206            }
207    
208            list = syntaxRegistry.iterator();
209            while ( list.hasNext() )
210            {
211                Syntax syntax = ( Syntax ) list.next();
212                resolve( syntax, errors );
213            }
214    
215            return errors;
216        }
217    
218    
219        /**
220         * Attempts to resolve the SyntaxChecker associated with a Syntax.
221         *
222         * @param syntax the Syntax to resolve the SyntaxChecker of
223         * @param errors the list of errors to add exceptions to
224         * @return true if it succeeds, false otherwise
225         */
226        private boolean resolve( Syntax syntax, List<Throwable> errors )
227        {
228            if ( syntax == null )
229            {
230                return true;
231            }
232    
233            try
234            {
235                syntax.getSyntaxChecker();
236                return true;
237            }
238            catch ( Exception e )
239            {
240                errors.add( e );
241                return false;
242            }
243        }
244    
245    
246        private boolean resolve( MatchingRule mr, List<Throwable> errors )
247        {
248            boolean isSuccess = true;
249    
250            if ( mr == null )
251            {
252                return true;
253            }
254    
255            try
256            {
257                if ( mr.getComparator() == null )
258                {
259                    String schema = matchingRuleRegistry.getSchemaName( mr.getOid() );
260                    errors.add( new NullPointerException( "matchingRule " + mr.getName() + " in schema " + schema
261                        + " with OID " + mr.getOid() + " has a null comparator" ) );
262                    isSuccess = false;
263                }
264            }
265            catch ( Exception e )
266            {
267                errors.add( e );
268                isSuccess = false;
269            }
270    
271            try
272            {
273                if ( mr.getNormalizer() == null )
274                {
275                    String schema = matchingRuleRegistry.getSchemaName( mr.getOid() );
276                    errors.add( new NullPointerException( "matchingRule " + mr.getName() + " in schema " + schema
277                        + " with OID " + mr.getOid() + " has a null normalizer" ) );
278                    isSuccess = false;
279                }
280            }
281            catch ( Exception e )
282            {
283                errors.add( e );
284                isSuccess = false;
285            }
286    
287            try
288            {
289                isSuccess &= resolve( mr.getSyntax(), errors );
290    
291                if ( mr.getSyntax() == null )
292                {
293                    String schema = matchingRuleRegistry.getSchemaName( mr.getOid() );
294                    errors.add( new NullPointerException( "matchingRule " + mr.getName() + " in schema " + schema
295                        + " with OID " + mr.getOid() + " has a null Syntax" ) );
296                    isSuccess = false;
297                }
298            }
299            catch ( Exception e )
300            {
301                errors.add( e );
302                isSuccess = false;
303            }
304    
305            return isSuccess;
306        }
307    
308    
309        private boolean resolve( AttributeType at, List<Throwable> errors )
310        {
311            boolean isSuccess = true;
312    
313            boolean hasMatchingRule = false;
314    
315            if ( at == null )
316            {
317                return true;
318            }
319    
320            try
321            {
322                isSuccess &= resolve( at.getSuperior(), errors );
323            }
324            catch ( Exception e )
325            {
326                errors.add( e );
327                isSuccess = false;
328            }
329    
330            try
331            {
332                isSuccess &= resolve( at.getEquality(), errors );
333    
334                if ( at.getEquality() != null )
335                {
336                    hasMatchingRule |= true;
337                }
338            }
339            catch ( Exception e )
340            {
341                errors.add( e );
342                isSuccess = false;
343            }
344    
345            try
346            {
347                isSuccess &= resolve( at.getOrdering(), errors );
348    
349                if ( at.getOrdering() != null )
350                {
351                    hasMatchingRule |= true;
352                }
353            }
354            catch ( Exception e )
355            {
356                errors.add( e );
357                isSuccess = false;
358            }
359    
360            try
361            {
362                isSuccess &= resolve( at.getSubstr(), errors );
363    
364                if ( at.getSubstr() != null )
365                {
366                    hasMatchingRule |= true;
367                }
368            }
369            catch ( Exception e )
370            {
371                errors.add( e );
372                isSuccess = false;
373            }
374    
375            try
376            {
377                isSuccess &= resolve( at.getSyntax(), errors );
378    
379                if ( at.getSyntax() == null )
380                {
381                    String schema = attributeTypeRegistry.getSchemaName( at.getOid() );
382    
383                    errors.add( new NullPointerException( "attributeType " + at.getName() + " in schema " + schema
384                        + " with OID " + at.getOid() + " has a null Syntax" ) );
385    
386                    isSuccess = false;
387                }
388            }
389            catch ( Exception e )
390            {
391                errors.add( e );
392                isSuccess = false;
393            }
394    
395            //        try
396            //        {
397            //            String schema = attributeTypeRegistry.getSchemaName( at.getOid() );
398            //            if ( ! hasMatchingRule && at.getSyntax().isHumanReadable() )
399            //            {
400            //                errors.add( new NullPointerException( "attributeType "
401            //                        + at.getName() + " in schema " + schema + " with OID "
402            //                        + at.getOid() + " has a no matchingRules defined" ) );
403            //                isSuccess = false;
404            //            }
405            //        }
406            //        catch ( NamingException e )
407            //        {
408            //            errors.add( e );
409            //            isSuccess = false;
410            //        }
411    
412            return isSuccess;
413        }
414    
415    
416        private boolean resolve( ObjectClass oc, List<Throwable> errors )
417        {
418            boolean isSuccess = true;
419    
420            if ( oc == null )
421            {
422                return true;
423            }
424    
425            ObjectClass[] superiors = new org.apache.directory.shared.ldap.schema.ObjectClass[0];
426    
427            try
428            {
429                superiors = oc.getSuperClasses();
430            }
431            catch ( Exception e )
432            {
433                superiors = new ObjectClass[0];
434                isSuccess = false;
435                errors.add( e );
436            }
437    
438            for ( int ii = 0; ii < superiors.length; ii++ )
439            {
440                isSuccess &= resolve( superiors[ii], errors );
441            }
442    
443            AttributeType[] mayList = new org.apache.directory.shared.ldap.schema.AttributeType[0];
444    
445            try
446            {
447                mayList = oc.getMayList();
448            }
449            catch ( Exception e )
450            {
451                mayList = new AttributeType[0];
452                isSuccess = false;
453                errors.add( e );
454            }
455    
456            for ( int ii = 0; ii < mayList.length; ii++ )
457            {
458                isSuccess &= resolve( mayList[ii], errors );
459            }
460    
461            AttributeType[] mustList = new org.apache.directory.shared.ldap.schema.AttributeType[0];
462    
463            try
464            {
465                mustList = oc.getMustList();
466            }
467            catch ( Exception e )
468            {
469                mustList = new AttributeType[0];
470                isSuccess = false;
471                errors.add( e );
472            }
473    
474            for ( int ii = 0; ii < mustList.length; ii++ )
475            {
476                isSuccess &= resolve( mustList[ii], errors );
477            }
478    
479            return isSuccess;
480        }
481    
482        
483        /**
484         * Alterations to the returned map of schema names to schema objects does not 
485         * change the map returned from this method.  The returned map is however mutable.
486         */
487        public Map<String, Schema> getLoadedSchemas()
488        {
489            return new HashMap<String,Schema>( loadedByName );
490        }
491    
492    
493        public void load( String schemaName ) throws Exception
494        {
495            load( schemaName, new Properties() );
496        }
497    
498    
499        public void load( String schemaName, Properties schemaProperties ) throws Exception
500        {
501            Schema schema = schemaLoader.getSchema( schemaName, schemaProperties );
502            
503            if ( schema.isDisabled() )
504            {
505                throw new Exception( "Disabled schemas cannot be loaded into registries." );
506            }
507            
508            loadedByName.put( schema.getSchemaName(), schema );
509            schemaLoader.load( schema, this, false );
510        }
511        
512        
513        public void unload( String schemaName ) throws Exception
514        {
515            disableSchema( ditStructureRuleRegistry, schemaName );
516            disableSchema( ditContentRuleRegistry, schemaName );
517            disableSchema( matchingRuleUseRegistry, schemaName );
518            disableSchema( nameFormRegistry, schemaName );
519            disableSchema( objectClassRegistry, schemaName );
520            disableSchema( attributeTypeRegistry, schemaName );
521            disableSchema( matchingRuleRegistry, schemaName );
522            disableSchema( syntaxRegistry, schemaName );
523    
524            normalizerRegistry.unregisterSchemaElements( schemaName );
525            comparatorRegistry.unregisterSchemaElements( schemaName );
526            syntaxCheckerRegistry.unregisterSchemaElements( schemaName );
527            loadedByName.remove( schemaName );
528        }
529    
530    
531        private void disableSchema( SchemaObjectRegistry registry, String schemaName ) throws Exception
532        {
533            Iterator<? extends SchemaObject> objects = registry.iterator();
534            List<String> unregistered = new ArrayList<String>();
535            while ( objects.hasNext() )
536            {
537                SchemaObject obj = objects.next();
538                if ( obj.getSchema().equalsIgnoreCase( schemaName ) )
539                {
540                    unregistered.add( obj.getOid() );
541                }
542            }
543            
544            for ( String oid : unregistered )
545            {
546                registry.unregister( oid );
547            }
548        }
549        
550    
551        public SchemaLoader getSchemaLoader()
552        {
553            return schemaLoader;
554        }
555    
556    
557        public Schema getSchema( String schemaName )
558        {
559            return this.loadedByName.get( schemaName );
560        }
561    
562    
563        public void addToLoadedSet( Schema schema )
564        {
565            loadedByName.put( schema.getSchemaName(), schema );
566        }
567    
568    
569        public void removeFromLoadedSet( String schemaName )
570        {
571            loadedByName.remove( schemaName );
572        }
573    }