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.registries;
021    
022    
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.HashMap;
026    import java.util.HashSet;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Set;
030    
031    import org.apache.directory.shared.i18n.I18n;
032    import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
033    import org.apache.directory.shared.ldap.constants.SchemaConstants;
034    import org.apache.directory.shared.ldap.entry.Entry;
035    import org.apache.directory.shared.ldap.entry.EntryAttribute;
036    import org.apache.directory.shared.ldap.entry.Value;
037    import org.apache.directory.shared.ldap.util.StringTools;
038    import org.slf4j.Logger;
039    import org.slf4j.LoggerFactory;
040    
041    
042    /**
043     * An abstract class with a utility method and setListener() implemented.
044     *
045     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
046     * @version $Rev$
047     */
048    public abstract class AbstractSchemaLoader implements SchemaLoader
049    {
050        /** static class logger */
051        private static final Logger LOG = LoggerFactory.getLogger( AbstractSchemaLoader.class );
052    
053        protected SchemaLoaderListener listener;
054    
055        /** 
056         * A map of all available schema names to schema objects. This map is 
057         * populated when this class is created with all the schemas present in
058         * the LDIF based schema repository.
059         */
060        protected final Map<String, Schema> schemaMap = new HashMap<String, Schema>();
061    
062    
063        public void setListener( SchemaLoaderListener listener )
064        {
065            this.listener = listener;
066        }
067    
068    
069        protected final void notifyListenerOrRegistries( Schema schema, Registries registries )
070        {
071            if ( listener != null )
072            {
073                listener.schemaLoaded( schema );
074            }
075    
076            if ( registries instanceof SchemaLoaderListener )
077            {
078                if ( registries != listener )
079                {
080                    SchemaLoaderListener listener = ( SchemaLoaderListener ) registries;
081                    listener.schemaLoaded( schema );
082                }
083            }
084        }
085    
086    
087        /**
088         * {@inheritDoc}
089         */
090        public final Collection<Schema> getAllEnabled() throws Exception
091        {
092            Collection<Schema> enabledSchemas = new ArrayList<Schema>();
093            
094            for ( Schema schema : schemaMap.values() )
095            {
096                if ( schema.isEnabled() )
097                {
098                    enabledSchemas.add( schema );
099                }
100            }
101            
102            return enabledSchemas;
103        }
104    
105    
106        /**
107         * {@inheritDoc}
108         */
109        public final Collection<Schema> getAllSchemas() throws Exception
110        {
111            return schemaMap.values();
112        }
113    
114    
115        /**
116         * {@inheritDoc}
117         */
118        public Schema getSchema( String schemaName )
119        {
120            return schemaMap.get( StringTools.toLowerCase( schemaName ) );
121        }
122        
123        
124        /**
125         * {@inheritDoc}
126         */
127        public void addSchema( Schema schema )
128        {
129            schemaMap.put( schema.getSchemaName(), schema );
130        }
131        
132        
133        /**
134         * {@inheritDoc}
135         */
136        public void removeSchema( Schema schema )
137        {
138            schemaMap.remove( schema.getSchemaName() );
139        }
140    
141    
142        protected Schema getSchema( Entry entry ) throws Exception
143        {
144            EntryAttribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
145            boolean isSchema = false;
146    
147            for ( Value<?> value : objectClasses )
148            {
149                if ( MetaSchemaConstants.META_SCHEMA_OC.equalsIgnoreCase( value.getString() ) )
150                {
151                    isSchema = true;
152                    break;
153                }
154            }
155    
156            if ( !isSchema )
157            {
158                return null;
159            }
160    
161            String name;
162            String owner;
163            String[] dependencies = StringTools.EMPTY_STRINGS;
164            boolean isDisabled = false;
165    
166            if ( entry == null )
167            {
168                throw new NullPointerException( I18n.err( I18n.ERR_04261 ) );
169            }
170    
171            if ( entry.get( SchemaConstants.CN_AT ) == null )
172            {
173                throw new NullPointerException( I18n.err( I18n.ERR_04262 ) );
174            }
175    
176            name = entry.get( SchemaConstants.CN_AT ).getString();
177    
178            if ( entry.get( SchemaConstants.CREATORS_NAME_AT ) == null )
179            {
180                throw new NullPointerException( "entry must have a valid " + SchemaConstants.CREATORS_NAME_AT
181                    + " attribute" );
182            }
183    
184            owner = entry.get( SchemaConstants.CREATORS_NAME_AT ).getString();
185    
186            if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
187            {
188                String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
189                value = value.toUpperCase();
190                isDisabled = value.equals( "TRUE" );
191            }
192    
193            if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
194            {
195                Set<String> depsSet = new HashSet<String>();
196                EntryAttribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
197    
198                for ( Value<?> value : depsAttr )
199                {
200                    depsSet.add( value.getString() );
201                }
202    
203                dependencies = depsSet.toArray( StringTools.EMPTY_STRINGS );
204            }
205    
206            return new DefaultSchema( name, owner, dependencies, isDisabled )
207            {
208            };
209        }
210    
211    
212        /**
213         * {@inheritDoc}
214         *
215        public List<Throwable> loadWithDependencies( Registries registries, boolean check, Schema... schemas ) throws Exception
216        {
217            // Relax the controls at first
218            List<Throwable> errors = new ArrayList<Throwable>();
219            boolean wasRelaxed = registries.isRelaxed();
220            registries.setRelaxed( true );
221    
222            Map<String,Schema> notLoaded = new HashMap<String,Schema>();
223            
224            for ( Schema schema : schemas )
225            {
226                if ( ! registries.isSchemaLoaded( schema.getSchemaName() ) )
227                {
228                    notLoaded.put( schema.getSchemaName(), schema );
229                }
230            }
231            
232            for ( Schema schema : notLoaded.values() )
233            {
234                Stack<String> beenthere = new Stack<String>();
235                loadDepsFirst( schema, beenthere, notLoaded, schema, registries );
236            }
237            
238            // At the end, check the registries if required
239            if ( check )
240            {
241                errors = registries.checkRefInteg();
242            }
243            
244            // Restore the Registries isRelaxed flag
245            registries.setRelaxed( wasRelaxed );
246            
247            return errors;
248        }
249        
250        
251        /**
252         * Register the comparator contained in the given LdifEntry into the registries. 
253         *
254         * @param registries The Registries
255         * @param entry The LdifEntry containing the comparator description
256         * @param schema The associated schema
257         * @throws Exception If the registering failed
258         *
259        protected LdapComparator<?> registerComparator( Registries registries, LdifEntry entry, Schema schema ) 
260            throws Exception
261        {
262            return registerComparator( registries, entry.getEntry(), schema );
263        }
264        
265        
266        /**
267         * Register the comparator contained in the given Entry into the registries. 
268         *
269         * @param registries The Registries
270         * @param entry The Entry containing the comparator description
271         * @param schema The associated schema
272         * @throws Exception If the registering failed
273         *
274        protected LdapComparator<?> registerComparator( Registries registries, Entry entry, Schema schema ) 
275            throws Exception
276        {
277            LdapComparator<?> comparator = 
278                factory.getLdapComparator( entry, registries, schema.getSchemaName() );
279            comparator.setOid( entry.get( MetaSchemaConstants.M_OID_AT ).getString() );
280    
281            if ( registries.isRelaxed() )
282            {
283                if ( registries.acceptDisabled() )
284                {
285                    registries.register( comparator );
286                }
287                else if ( schema.isEnabled() && comparator.isEnabled() )
288                {
289                    registries.register( comparator );
290                }
291            }
292            else
293            {
294                if ( schema.isEnabled() && comparator.isEnabled() )
295                {
296                    registries.register( comparator );
297                }
298            }
299            
300            return comparator;
301        }
302        
303        
304        /**
305         * Register the SyntaxChecker contained in the given LdifEntry into the registries. 
306         *
307         * @param registries The Registries
308         * @param entry The LdifEntry containing the SyntaxChecker description
309         * @param schema The associated schema
310         * @return the created SyntaxChecker instance
311         * @throws Exception If the registering failed
312         *
313        protected SyntaxChecker registerSyntaxChecker( Registries registries, LdifEntry entry, Schema schema) 
314            throws Exception
315        {
316            SyntaxChecker syntaxChecker = 
317                factory.getSyntaxChecker( entry.getEntry(), registries, schema.getSchemaName() );
318            syntaxChecker.setOid( entry.get( MetaSchemaConstants.M_OID_AT ).getString() );
319    
320            if ( registries.isRelaxed() )
321            {
322                if ( registries.acceptDisabled() )
323                {
324                    registries.register( syntaxChecker );
325                }
326                else if ( schema.isEnabled() && syntaxChecker.isEnabled() )
327                {
328                    registries.register( syntaxChecker );
329                }
330            }
331            else
332            {
333                if ( schema.isEnabled() && syntaxChecker.isEnabled() )
334                {
335                    registries.register( syntaxChecker );
336                }
337            }
338            
339            return syntaxChecker;
340        }
341        
342        
343        /**
344         * Register the Normalizer contained in the given LdifEntry into the registries. 
345         *
346         * @param registries The Registries
347         * @param entry The LdifEntry containing the Normalizer description
348         * @param schema The associated schema
349         * @return the created Normalizer instance
350         * @throws Exception If the registering failed
351         *
352        protected Normalizer registerNormalizer( Registries registries, LdifEntry entry, Schema schema) 
353            throws Exception
354        {
355            Normalizer normalizer =
356                factory.getNormalizer( entry.getEntry(), registries, schema.getSchemaName() );
357            
358            if ( registries.isRelaxed() )
359            {
360                if ( registries.acceptDisabled() )
361                {
362                    registries.register( normalizer );
363                }
364                else if ( schema.isEnabled() && normalizer.isEnabled() )
365                {
366                    registries.register( normalizer );
367                }
368            }
369            else
370            {
371                if ( schema.isEnabled() && normalizer.isEnabled() )
372                {
373                    registries.register( normalizer );
374                }
375            }
376            
377            return normalizer;
378        }
379        
380        
381        /**
382         * Register the MatchingRule contained in the given LdifEntry into the registries. 
383         *
384         * @param registries The Registries
385         * @param entry The LdifEntry containing the MatchingRule description
386         * @param schema The associated schema
387         * @return the created MatchingRule instance
388         * @throws Exception If the registering failed
389         *
390        protected MatchingRule registerMatchingRule( Registries registries, LdifEntry entry, Schema schema) 
391            throws Exception
392        {
393            MatchingRule matchingRule = factory.getMatchingRule( 
394                entry.getEntry(), registries, schema.getSchemaName() );
395    
396            if ( registries.isRelaxed() )
397            {
398                if ( registries.acceptDisabled() )
399                {
400                    registries.register( matchingRule );
401                }
402                else if ( schema.isEnabled() && matchingRule.isEnabled() )
403                {
404                    registries.register( matchingRule );
405                }
406            }
407            else
408            {
409                if ( schema.isEnabled() && matchingRule.isEnabled() )
410                {
411                    registries.register( matchingRule );
412                }
413            }
414            
415            return matchingRule;
416        }
417        
418        
419        /**
420         * Register the Syntax contained in the given LdifEntry into the registries. 
421         *
422         * @param registries The Registries
423         * @param entry The LdifEntry containing the Syntax description
424         * @param schema The associated schema
425         * @return the created Syntax instance
426         * @throws Exception If the registering failed
427         *
428        protected LdapSyntax registerSyntax( Registries registries, LdifEntry entry, Schema schema) 
429            throws Exception
430        {
431            LdapSyntax syntax = factory.getSyntax( 
432                entry.getEntry(), registries, schema.getSchemaName() );
433    
434            if ( registries.isRelaxed() )
435            {
436                if ( registries.acceptDisabled() )
437                {
438                    registries.register( syntax );
439                }
440                else if ( schema.isEnabled() && syntax.isEnabled() )
441                {
442                    registries.register( syntax );
443                }
444            }
445            else
446            {
447                if ( schema.isEnabled() && syntax.isEnabled() )
448                {
449                    registries.register( syntax );
450                }
451            }
452            
453            return syntax;
454        }
455        
456        
457        /**
458         * Register the AttributeType contained in the given LdifEntry into the registries. 
459         *
460         * @param registries The Registries
461         * @param entry The LdifEntry containing the AttributeType description
462         * @param schema The associated schema
463         * @return the created AttributeType instance
464         * @throws Exception If the registering failed
465         *
466        protected AttributeType registerAttributeType( Registries registries, LdifEntry entry, Schema schema ) 
467            throws Exception
468        {
469            AttributeType attributeType = factory.getAttributeType( entry.getEntry(), registries, schema.getSchemaName() );
470            
471            if ( registries.isRelaxed() )
472            {
473                if ( registries.acceptDisabled() )
474                {
475                    registries.register( attributeType );
476                }
477                else if ( schema.isEnabled() && attributeType.isEnabled() )
478                {
479                    registries.register( attributeType );
480                }
481            }
482            else
483            {
484                if ( schema.isEnabled() && attributeType.isEnabled() )
485                {
486                    registries.register( attributeType );
487                }
488            }
489            
490            return attributeType;
491        }
492        
493        
494        /**
495         * Register the MatchingRuleUse contained in the given LdifEntry into the registries. 
496         *
497         * @param registries The Registries
498         * @param entry The LdifEntry containing the MatchingRuleUse description
499         * @param schema The associated schema
500         * @return the created MatchingRuleUse instance
501         * @throws Exception If the registering failed
502         *
503        protected MatchingRuleUse registerMatchingRuleUse( Registries registries, LdifEntry entry, Schema schema) 
504            throws Exception
505        {
506            throw new NotImplementedException( "Need to implement factory " +
507                    "method for creating a MatchingRuleUse" );
508        }
509        
510        
511        /**
512         * Register the NameForm contained in the given LdifEntry into the registries. 
513         *
514         * @param registries The Registries
515         * @param entry The LdifEntry containing the NameForm description
516         * @param schema The associated schema
517         * @return the created NameForm instance
518         * @throws Exception If the registering failed
519         *
520        protected NameForm registerNameForm( Registries registries, LdifEntry entry, Schema schema) 
521            throws Exception
522        {
523            throw new NotImplementedException( "Need to implement factory " +
524                    "method for creating a NameForm" );
525        }
526        
527        
528        /**
529         * Register the DitContentRule contained in the given LdifEntry into the registries. 
530         *
531         * @param registries The Registries
532         * @param entry The LdifEntry containing the DitContentRule description
533         * @param schema The associated schema
534         * @return the created DitContentRule instance
535         * @throws Exception If the registering failed
536         *
537        protected DITContentRule registerDitContentRule( Registries registries, LdifEntry entry, Schema schema) 
538            throws Exception
539        {
540            throw new NotImplementedException( "Need to implement factory " +
541                    "method for creating a DitContentRule" );
542        }
543        
544        
545        /**
546         * Register the DitStructureRule contained in the given LdifEntry into the registries. 
547         *
548         * @param registries The Registries
549         * @param entry The LdifEntry containing the DitStructureRule description
550         * @param schema The associated schema
551         * @return the created DitStructureRule instance
552         * @throws Exception If the registering failed
553         *
554        protected DITStructureRule registerDitStructureRule( Registries registries, LdifEntry entry, Schema schema) 
555            throws Exception
556        {
557            throw new NotImplementedException( "Need to implement factory " +
558                    "method for creating a DitStructureRule" );
559        }
560    
561    
562        /**
563         * Register the ObjectClass contained in the given LdifEntry into the registries. 
564         *
565         * @param registries The Registries
566         * @param entry The LdifEntry containing the ObjectClass description
567         * @param schema The associated schema
568         * @return the created ObjectClass instance
569         * @throws Exception If the registering failed
570         *
571        protected ObjectClass registerObjectClass( Registries registries, LdifEntry entry, Schema schema) 
572            throws Exception
573        {
574            return registerObjectClass( registries, entry.getEntry(), schema );
575        }
576    
577    
578        /**
579         * Register the ObjectClass contained in the given LdifEntry into the registries. 
580         *
581         * @param registries The Registries
582         * @param entry The Entry containing the ObjectClass description
583         * @param schema The associated schema
584         * @return the created ObjectClass instance
585         * @throws Exception If the registering failed
586         *
587        protected ObjectClass registerObjectClass( Registries registries, Entry entry, Schema schema) 
588            throws Exception
589        {
590            ObjectClass objectClass = factory.getObjectClass( entry, registries, schema.getSchemaName() );
591    
592            if ( registries.isRelaxed() )
593            {
594                if ( registries.acceptDisabled() )
595                {
596                    registries.register( objectClass );
597                }
598                else if ( schema.isEnabled() && objectClass.isEnabled() )
599                {
600                    registries.register( objectClass );
601                }
602            }
603            else
604            {
605                if ( schema.isEnabled() && objectClass.isEnabled() )
606                {
607                    registries.register( objectClass );
608                }
609            }
610            
611            return objectClass;
612        }
613        
614        
615        public EntityFactory getFactory()
616        {
617            return factory;
618        }
619        */
620    
621        public Object getDao()
622        {
623            return null;
624        }
625    
626    
627        private Schema[] buildSchemaArray( String... schemaNames ) throws Exception
628        {
629            Schema[] schemas = new Schema[schemaNames.length];
630            int pos = 0;
631    
632            for ( String schemaName : schemaNames )
633            {
634                schemas[pos++] = getSchema( schemaName );
635            }
636    
637            return schemas;
638        }
639    
640    
641        /**
642         * {@inheritDoc}
643         */
644        public List<Entry> loadAttributeTypes( String... schemaNames ) throws Exception
645        {
646            if ( schemaNames == null )
647            {
648                return new ArrayList<Entry>();
649            }
650    
651            return loadAttributeTypes( buildSchemaArray( schemaNames ) );
652        }
653    
654    
655        /**
656         * {@inheritDoc}
657         */
658        public List<Entry> loadComparators( String... schemaNames ) throws Exception
659        {
660            if ( schemaNames == null )
661            {
662                return new ArrayList<Entry>();
663            }
664    
665            return loadComparators( buildSchemaArray( schemaNames ) );
666        }
667    
668    
669        /**
670         * {@inheritDoc}
671         */
672        public List<Entry> loadDitContentRules( String... schemaNames ) throws Exception
673        {
674            if ( schemaNames == null )
675            {
676                return new ArrayList<Entry>();
677            }
678    
679            return loadDitContentRules( buildSchemaArray( schemaNames ) );
680        }
681    
682    
683        /**
684         * {@inheritDoc}
685         */
686        public List<Entry> loadDitStructureRules( String... schemaNames ) throws Exception
687        {
688            if ( schemaNames == null )
689            {
690                return new ArrayList<Entry>();
691            }
692    
693            return loadDitStructureRules( buildSchemaArray( schemaNames ) );
694        }
695    
696    
697        /**
698         * {@inheritDoc}
699         */
700        public List<Entry> loadMatchingRules( String... schemaNames ) throws Exception
701        {
702            if ( schemaNames == null )
703            {
704                return new ArrayList<Entry>();
705            }
706    
707            return loadMatchingRules( buildSchemaArray( schemaNames ) );
708        }
709    
710    
711        /**
712         * {@inheritDoc}
713         */
714        public List<Entry> loadMatchingRuleUses( String... schemaNames ) throws Exception
715        {
716            if ( schemaNames == null )
717            {
718                return new ArrayList<Entry>();
719            }
720    
721            return loadMatchingRuleUses( buildSchemaArray( schemaNames ) );
722        }
723    
724    
725        /**
726         * {@inheritDoc}
727         */
728        public List<Entry> loadNameForms( String... schemaNames ) throws Exception
729        {
730            if ( schemaNames == null )
731            {
732                return new ArrayList<Entry>();
733            }
734    
735            return loadNameForms( buildSchemaArray( schemaNames ) );
736        }
737    
738    
739        /**
740         * {@inheritDoc}
741         */
742        public List<Entry> loadNormalizers( String... schemaNames ) throws Exception
743        {
744            if ( schemaNames == null )
745            {
746                return new ArrayList<Entry>();
747            }
748    
749            return loadNormalizers( buildSchemaArray( schemaNames ) );
750        }
751    
752    
753        /**
754         * {@inheritDoc}
755         */
756        public List<Entry> loadObjectClasses( String... schemaNames ) throws Exception
757        {
758            if ( schemaNames == null )
759            {
760                return new ArrayList<Entry>();
761            }
762    
763            return loadObjectClasses( buildSchemaArray( schemaNames ) );
764        }
765    
766    
767        /**
768         * {@inheritDoc}
769         */
770        public List<Entry> loadSyntaxes( String... schemaNames ) throws Exception
771        {
772            if ( schemaNames == null )
773            {
774                return new ArrayList<Entry>();
775            }
776    
777            return loadSyntaxes( buildSchemaArray( schemaNames ) );
778        }
779    
780    
781        /**
782         * {@inheritDoc}
783         */
784        public List<Entry> loadSyntaxCheckers( String... schemaNames ) throws Exception
785        {
786            if ( schemaNames == null )
787            {
788                return new ArrayList<Entry>();
789            }
790    
791            return loadSyntaxCheckers( buildSchemaArray( schemaNames ) );
792        }
793    }