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