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.schema.loader;
021
022
023import java.io.File;
024import java.io.FileNotFoundException;
025import java.io.FilenameFilter;
026import java.io.IOException;
027import java.util.ArrayList;
028import java.util.List;
029
030import org.apache.directory.api.i18n.I18n;
031import org.apache.directory.api.ldap.model.constants.SchemaConstants;
032import org.apache.directory.api.ldap.model.entry.Entry;
033import org.apache.directory.api.ldap.model.exception.LdapException;
034import org.apache.directory.api.ldap.model.ldif.LdifEntry;
035import org.apache.directory.api.ldap.model.ldif.LdifReader;
036import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
037import org.apache.directory.api.ldap.model.schema.registries.Schema;
038import org.apache.directory.api.util.Strings;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042
043/**
044 * Loads schema data from LDIF files containing entries representing schema
045 * objects, using the meta schema format.
046 *
047 * This class is used only for tests.
048 * 
049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
050 */
051public class LdifSchemaLoader extends AbstractSchemaLoader
052{
053    /** ldif file extension used */
054    private static final String LDIF_EXT = "ldif";
055
056    /** ou=schema LDIF file name */
057    private static final String OU_SCHEMA_LDIF = "ou=schema." + LDIF_EXT;
058
059    /** static class logger */
060    private static final Logger LOG = LoggerFactory.getLogger( LdifSchemaLoader.class );
061
062    /** Speedup for DEBUG mode */
063    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
064
065    /** directory containing the schema LDIF file for ou=schema */
066    private final File baseDirectory;
067
068    /** a filter for listing all the LDIF files within a directory */
069    private final FilenameFilter ldifFilter = new FilenameFilter()
070    {
071        @Override
072        public boolean accept( File file, String name )
073        {
074            return name.endsWith( LDIF_EXT );
075        }
076    };
077
078
079    /**
080     * Creates a new LDIF based SchemaLoader. The constructor checks to make
081     * sure the supplied base directory exists and contains a schema.ldif file
082     * and if not complains about it.
083     *
084     * @param baseDirectory the schema LDIF base directory
085     * @throws LdapException if the base directory does not exist or does not
086     * a valid schema.ldif file
087     * @throws IOException If we can't load the schema
088     */
089    public LdifSchemaLoader( File baseDirectory ) throws LdapException, IOException
090    {
091        this.baseDirectory = baseDirectory;
092
093        if ( !baseDirectory.exists() )
094        {
095            String msg = "Provided baseDirectory '" + baseDirectory.getAbsolutePath() + "' does not exist.";
096            LOG.error( msg );
097            throw new IllegalArgumentException( msg );
098        }
099
100        File schemaLdif = new File( baseDirectory, OU_SCHEMA_LDIF );
101
102        if ( !schemaLdif.exists() )
103        {
104            String msg = I18n.err( I18n.ERR_10004, schemaLdif.getAbsolutePath() );
105            LOG.error( msg );
106            throw new FileNotFoundException( msg );
107        }
108
109        if ( IS_DEBUG )
110        {
111            LOG.debug( "Using '{}' as the base schema load directory.", baseDirectory );
112        }
113
114        initializeSchemas();
115    }
116
117
118    /**
119     * Scans for LDIF files just describing the various schema contained in
120     * the schema repository.
121     *
122     * @throws LdapException
123     */
124    private void initializeSchemas() throws LdapException, IOException
125    {
126        if ( IS_DEBUG )
127        {
128            LOG.debug( "Initializing schema" );
129        }
130
131        File schemaDirectory = new File( baseDirectory, SchemaConstants.OU_SCHEMA );
132        String[] ldifFiles = schemaDirectory.list( ldifFilter );
133
134        if ( ldifFiles != null )
135        {
136            for ( String ldifFile : ldifFiles )
137            {
138                File file = new File( schemaDirectory, ldifFile );
139
140                try ( LdifReader reader = new LdifReader( file ) )
141                {
142                    LdifEntry entry = reader.next();
143                    Schema schema = getSchema( entry.getEntry() );
144
145                    if ( schema == null )
146                    {
147                        // The entry was not a schema, skip it
148                        continue;
149                    }
150
151                    schemaMap.put( schema.getSchemaName(), schema );
152
153                    if ( IS_DEBUG )
154                    {
155                        LOG.debug( "Schema Initialized ... \n{}", schema );
156                    }
157                }
158                catch ( LdapException e )
159                {
160                    LOG.error( I18n.err( I18n.ERR_10003, ldifFile ), e );
161                    throw e;
162                }
163            }
164        }
165    }
166
167
168    /**
169     * Utility method to get the file for a schema directory.
170     *
171     * @param schema the schema to get the file for
172     * @return the file for the specific schema directory
173     */
174    private File getSchemaDirectory( Schema schema )
175    {
176        return new File( new File( baseDirectory, SchemaConstants.OU_SCHEMA ), "cn="
177            + Strings.lowerCase( schema.getSchemaName() ) );
178    }
179
180
181    /**
182     * {@inheritDoc}
183     */
184    @Override
185    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
186    {
187        List<Entry> comparatorList = new ArrayList<>();
188
189        if ( schemas == null )
190        {
191            return comparatorList;
192        }
193
194        for ( Schema schema : schemas )
195        {
196            File comparatorsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.COMPARATORS_PATH );
197
198            if ( !comparatorsDirectory.exists() )
199            {
200                return comparatorList;
201            }
202
203            File[] comparators = comparatorsDirectory.listFiles( ldifFilter );
204
205            if ( comparators != null )
206            {
207                for ( File ldifFile : comparators )
208                {
209                    LdifReader reader = new LdifReader( ldifFile );
210                    LdifEntry entry = reader.next();
211                    reader.close();
212
213                    comparatorList.add( entry.getEntry() );
214                }
215            }
216        }
217
218        return comparatorList;
219    }
220
221
222    /**
223     * {@inheritDoc}
224     */
225    @Override
226    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
227    {
228        List<Entry> syntaxCheckerList = new ArrayList<>();
229
230        if ( schemas == null )
231        {
232            return syntaxCheckerList;
233        }
234
235        for ( Schema schema : schemas )
236        {
237            File syntaxCheckersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAX_CHECKERS_PATH );
238
239            if ( !syntaxCheckersDirectory.exists() )
240            {
241                return syntaxCheckerList;
242            }
243
244            File[] syntaxCheckerFiles = syntaxCheckersDirectory.listFiles( ldifFilter );
245
246            if ( syntaxCheckerFiles != null )
247            {
248                for ( File ldifFile : syntaxCheckerFiles )
249                {
250                    LdifReader reader = new LdifReader( ldifFile );
251                    LdifEntry entry = reader.next();
252                    reader.close();
253
254                    syntaxCheckerList.add( entry.getEntry() );
255                }
256            }
257        }
258
259        return syntaxCheckerList;
260    }
261
262
263    /**
264     * {@inheritDoc}
265     */
266    @Override
267    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
268    {
269        List<Entry> normalizerList = new ArrayList<>();
270
271        if ( schemas == null )
272        {
273            return normalizerList;
274        }
275
276        for ( Schema schema : schemas )
277        {
278            File normalizersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NORMALIZERS_PATH );
279
280            if ( !normalizersDirectory.exists() )
281            {
282                return normalizerList;
283            }
284
285            File[] normalizerFiles = normalizersDirectory.listFiles( ldifFilter );
286
287            if ( normalizerFiles != null )
288            {
289                for ( File ldifFile : normalizerFiles )
290                {
291                    LdifReader reader = new LdifReader( ldifFile );
292                    LdifEntry entry = reader.next();
293                    reader.close();
294
295                    normalizerList.add( entry.getEntry() );
296                }
297            }
298        }
299
300        return normalizerList;
301    }
302
303
304    /**
305     * {@inheritDoc}
306     */
307    @Override
308    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
309    {
310        List<Entry> matchingRuleList = new ArrayList<>();
311
312        if ( schemas == null )
313        {
314            return matchingRuleList;
315        }
316
317        for ( Schema schema : schemas )
318        {
319            File matchingRulesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.MATCHING_RULES_PATH );
320
321            if ( !matchingRulesDirectory.exists() )
322            {
323                return matchingRuleList;
324            }
325
326            File[] matchingRuleFiles = matchingRulesDirectory.listFiles( ldifFilter );
327
328            if ( matchingRuleFiles != null )
329            {
330                for ( File ldifFile : matchingRuleFiles )
331                {
332                    LdifReader reader = new LdifReader( ldifFile );
333                    LdifEntry entry = reader.next();
334                    reader.close();
335
336                    matchingRuleList.add( entry.getEntry() );
337                }
338            }
339        }
340
341        return matchingRuleList;
342    }
343
344
345    /**
346     * {@inheritDoc}
347     */
348    @Override
349    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
350    {
351        List<Entry> syntaxList = new ArrayList<>();
352
353        if ( schemas == null )
354        {
355            return syntaxList;
356        }
357
358        for ( Schema schema : schemas )
359        {
360            File syntaxesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAXES_PATH );
361
362            if ( !syntaxesDirectory.exists() )
363            {
364                return syntaxList;
365            }
366
367            File[] syntaxFiles = syntaxesDirectory.listFiles( ldifFilter );
368
369            if ( syntaxFiles != null )
370            {
371                for ( File ldifFile : syntaxFiles )
372                {
373                    LdifReader reader = new LdifReader( ldifFile );
374                    LdifEntry entry = reader.next();
375                    reader.close();
376
377                    syntaxList.add( entry.getEntry() );
378                }
379            }
380        }
381
382        return syntaxList;
383    }
384
385
386    /**
387     * {@inheritDoc}
388     */
389    @Override
390    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
391    {
392        List<Entry> attributeTypeList = new ArrayList<>();
393
394        if ( schemas == null )
395        {
396            return attributeTypeList;
397        }
398
399        for ( Schema schema : schemas )
400        {
401            // check that the attributeTypes directory exists for the schema
402            File attributeTypesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.ATTRIBUTE_TYPES_PATH );
403
404            if ( !attributeTypesDirectory.exists() )
405            {
406                return attributeTypeList;
407            }
408
409            // get list of attributeType LDIF schema files in attributeTypes
410            File[] attributeTypeFiles = attributeTypesDirectory.listFiles( ldifFilter );
411
412            if ( attributeTypeFiles != null )
413            {
414                for ( File ldifFile : attributeTypeFiles )
415                {
416                    LdifReader reader = new LdifReader( ldifFile );
417                    LdifEntry entry = reader.next();
418                    reader.close();
419
420                    attributeTypeList.add( entry.getEntry() );
421                }
422            }
423        }
424
425        return attributeTypeList;
426    }
427
428
429    /**
430     * {@inheritDoc}
431     */
432    @Override
433    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
434    {
435        List<Entry> matchingRuleUseList = new ArrayList<>();
436
437        if ( schemas == null )
438        {
439            return matchingRuleUseList;
440        }
441
442        for ( Schema schema : schemas )
443        {
444            File matchingRuleUsesDirectory = new File( getSchemaDirectory( schema ),
445                SchemaConstants.MATCHING_RULE_USE_PATH );
446
447            if ( !matchingRuleUsesDirectory.exists() )
448            {
449                return matchingRuleUseList;
450            }
451
452            File[] matchingRuleUseFiles = matchingRuleUsesDirectory.listFiles( ldifFilter );
453
454            if ( matchingRuleUseFiles != null )
455            {
456                for ( File ldifFile : matchingRuleUseFiles )
457                {
458                    LdifReader reader = new LdifReader( ldifFile );
459                    LdifEntry entry = reader.next();
460                    reader.close();
461
462                    matchingRuleUseList.add( entry.getEntry() );
463                }
464            }
465        }
466
467        return matchingRuleUseList;
468    }
469
470
471    /**
472     * {@inheritDoc}
473     */
474    @Override
475    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
476    {
477        List<Entry> nameFormList = new ArrayList<>();
478
479        if ( schemas == null )
480        {
481            return nameFormList;
482        }
483
484        for ( Schema schema : schemas )
485        {
486            File nameFormsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NAME_FORMS_PATH );
487
488            if ( !nameFormsDirectory.exists() )
489            {
490                return nameFormList;
491            }
492
493            File[] nameFormFiles = nameFormsDirectory.listFiles( ldifFilter );
494
495            if ( nameFormFiles != null )
496            {
497                for ( File ldifFile : nameFormFiles )
498                {
499                    LdifReader reader = new LdifReader( ldifFile );
500                    LdifEntry entry = reader.next();
501                    reader.close();
502
503                    nameFormList.add( entry.getEntry() );
504                }
505            }
506        }
507
508        return nameFormList;
509    }
510
511
512    /**
513     * {@inheritDoc}
514     */
515    @Override
516    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
517    {
518        List<Entry> ditContentRuleList = new ArrayList<>();
519
520        if ( schemas == null )
521        {
522            return ditContentRuleList;
523        }
524
525        for ( Schema schema : schemas )
526        {
527            File ditContentRulesDirectory = new File( getSchemaDirectory( schema ),
528                SchemaConstants.DIT_CONTENT_RULES_PATH );
529
530            if ( !ditContentRulesDirectory.exists() )
531            {
532                return ditContentRuleList;
533            }
534
535            File[] ditContentRuleFiles = ditContentRulesDirectory.listFiles( ldifFilter );
536
537            if ( ditContentRuleFiles != null )
538            {
539                for ( File ldifFile : ditContentRuleFiles )
540                {
541                    LdifReader reader = new LdifReader( ldifFile );
542                    LdifEntry entry = reader.next();
543                    reader.close();
544
545                    ditContentRuleList.add( entry.getEntry() );
546                }
547            }
548        }
549
550        return ditContentRuleList;
551    }
552
553
554    /**
555     * {@inheritDoc}
556     */
557    @Override
558    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
559    {
560        List<Entry> ditStructureRuleList = new ArrayList<>();
561
562        if ( schemas == null )
563        {
564            return ditStructureRuleList;
565        }
566
567        for ( Schema schema : schemas )
568        {
569            File ditStructureRulesDirectory = new File( getSchemaDirectory( schema ),
570                SchemaConstants.DIT_STRUCTURE_RULES_PATH );
571
572            if ( !ditStructureRulesDirectory.exists() )
573            {
574                return ditStructureRuleList;
575            }
576
577            File[] ditStructureRuleFiles = ditStructureRulesDirectory.listFiles( ldifFilter );
578
579            if ( ditStructureRuleFiles != null )
580            {
581                for ( File ldifFile : ditStructureRuleFiles )
582                {
583                    LdifReader reader = new LdifReader( ldifFile );
584                    LdifEntry entry = reader.next();
585                    reader.close();
586
587                    ditStructureRuleList.add( entry.getEntry() );
588                }
589            }
590        }
591
592        return ditStructureRuleList;
593    }
594
595
596    /**
597     * {@inheritDoc}
598     */
599    @Override
600    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
601    {
602        List<Entry> objectClassList = new ArrayList<>();
603
604        if ( schemas == null )
605        {
606            return objectClassList;
607        }
608
609        for ( Schema schema : schemas )
610        {
611            // get objectClasses directory, check if exists, return if not
612            File objectClassesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.OBJECT_CLASSES_PATH );
613
614            if ( !objectClassesDirectory.exists() )
615            {
616                return objectClassList;
617            }
618
619            // get list of objectClass LDIF files from directory and load
620            File[] objectClassFiles = objectClassesDirectory.listFiles( ldifFilter );
621
622            if ( objectClassFiles != null )
623            {
624                for ( File ldifFile : objectClassFiles )
625                {
626                    LdifReader reader = new LdifReader( ldifFile );
627                    LdifEntry entry = reader.next();
628                    reader.close();
629
630                    objectClassList.add( entry.getEntry() );
631                }
632            }
633        }
634
635        return objectClassList;
636    }
637}