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