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.schemaloader;
021
022
023import java.io.File;
024import java.io.IOException;
025import java.io.InputStream;
026import java.net.URL;
027import java.util.ArrayList;
028import java.util.List;
029import java.util.Map;
030import java.util.regex.Pattern;
031
032import org.apache.directory.api.i18n.I18n;
033import org.apache.directory.api.ldap.model.constants.SchemaConstants;
034import org.apache.directory.api.ldap.model.entry.Entry;
035import org.apache.directory.api.ldap.model.exception.LdapException;
036import org.apache.directory.api.ldap.model.ldif.LdifEntry;
037import org.apache.directory.api.ldap.model.ldif.LdifReader;
038import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
039import org.apache.directory.api.ldap.model.schema.registries.Schema;
040import org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;
041import org.apache.directory.api.ldap.schemaextractor.impl.ResourceMap;
042import org.apache.directory.api.util.Strings;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046
047/**
048 * Loads schema data from LDIF files containing entries representing schema
049 * objects, using the meta schema format.
050 * 
051 * This class is used only for tests.
052 *
053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
054 */
055public class JarLdifSchemaLoader extends AbstractSchemaLoader
056{
057    /**
058     * Filesystem path separator pattern, either forward slash or backslash.
059     * java.util.regex.Pattern is immutable so only one instance is needed for all uses.
060     */
061    private static final String SEPARATOR_PATTERN = "[/\\Q\\\\E]";
062
063    /** ldif file extension used */
064    private static final String LDIF_EXT = "ldif";
065
066    /** static class logger */
067    private static final Logger LOG = LoggerFactory.getLogger( JarLdifSchemaLoader.class );
068
069    /** Speedup for DEBUG mode */
070    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
071
072    /** a map of all the resources in this jar */
073    private static final Map<String, Boolean> RESOURCE_MAP = ResourceMap.getResources( Pattern
074        .compile( "schema" + SEPARATOR_PATTERN + "ou=schema.*" ) );
075
076
077    /**
078     * Creates a new LDIF based SchemaLoader. The constructor checks to make
079     * sure the supplied base directory exists and contains a schema.ldif file
080     * and if not complains about it.
081     *
082     * @throws Exception if the base directory does not exist or does not
083     * a valid schema.ldif file
084     */
085    public JarLdifSchemaLoader() throws Exception
086    {
087        initializeSchemas();
088    }
089
090
091    private URL getResource( String resource, String msg ) throws IOException
092    {
093        if ( RESOURCE_MAP.get( resource ) )
094        {
095            return DefaultSchemaLdifExtractor.getUniqueResource( resource, msg );
096        }
097        else
098        {
099            return new File( resource ).toURI().toURL();
100        }
101    }
102
103
104    /**
105     * Scans for LDIF files just describing the various schema contained in
106     * the schema repository.
107     *
108     * @throws Exception
109     */
110    private void initializeSchemas() throws Exception
111    {
112        if ( IS_DEBUG )
113        {
114            LOG.debug( "Initializing schema" );
115        }
116
117        Pattern pat = Pattern.compile( "schema" + SEPARATOR_PATTERN + "ou=schema"
118            + SEPARATOR_PATTERN + "cn=[a-z0-9-_]*\\." + LDIF_EXT );
119
120        for ( String file : RESOURCE_MAP.keySet() )
121        {
122            if ( pat.matcher( file ).matches() )
123            {
124                URL resource = getResource( file, "schema LDIF file" );
125                InputStream in = resource.openStream();
126
127                try
128                {
129                    LdifReader reader = new LdifReader( in );
130                    LdifEntry entry = reader.next();
131                    reader.close();
132                    Schema schema = getSchema( entry.getEntry() );
133                    schemaMap.put( schema.getSchemaName(), schema );
134
135                    if ( IS_DEBUG )
136                    {
137                        LOG.debug( "Schema Initialized ... \n{}", schema );
138                    }
139                }
140                catch ( Exception e )
141                {
142                    LOG.error( I18n.err( I18n.ERR_10003, file ), e );
143                    throw e;
144                }
145                finally
146                {
147                    in.close();
148                }
149            }
150        }
151    }
152
153
154    /**
155     * Utility method to get a regex.Pattern fragment for the path for a schema directory.
156     *
157     * @param schema the schema to get the path for
158     * @return the regex.Pattern fragment for the path for the specified schema directory
159     */
160    private String getSchemaDirectoryString( Schema schema )
161    {
162        return "schema" + "/" + "ou=schema" + "/"
163            + "cn=" + Strings.lowerCase( schema.getSchemaName() ) + "/";
164    }
165
166
167    /**
168     * {@inheritDoc}
169     */
170    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
171    {
172        List<Entry> comparatorList = new ArrayList<Entry>();
173
174        if ( schemas == null )
175        {
176            return comparatorList;
177        }
178
179        for ( Schema schema : schemas )
180        {
181            String start = getSchemaDirectoryString( schema )
182                + SchemaConstants.COMPARATORS_PATH + "/" + "m-oid=";
183            String end = "." + LDIF_EXT;
184
185            for ( String resourcePath : RESOURCE_MAP.keySet() )
186            {
187                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
188                {
189                    URL resource = getResource( resourcePath, "comparator LDIF file" );
190                    LdifReader reader = new LdifReader( resource.openStream() );
191                    LdifEntry entry = reader.next();
192                    reader.close();
193
194                    comparatorList.add( entry.getEntry() );
195                }
196            }
197        }
198
199        return comparatorList;
200    }
201
202
203    /**
204     * {@inheritDoc}
205     */
206    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
207    {
208        List<Entry> syntaxCheckerList = new ArrayList<Entry>();
209
210        if ( schemas == null )
211        {
212            return syntaxCheckerList;
213        }
214
215        for ( Schema schema : schemas )
216        {
217            String start = getSchemaDirectoryString( schema )
218                + SchemaConstants.SYNTAX_CHECKERS_PATH + "/" + "m-oid=";
219            String end = "." + LDIF_EXT;
220
221            for ( String resourcePath : RESOURCE_MAP.keySet() )
222            {
223                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
224                {
225                    URL resource = getResource( resourcePath, "syntaxChecker LDIF file" );
226                    LdifReader reader = new LdifReader( resource.openStream() );
227                    LdifEntry entry = reader.next();
228                    reader.close();
229
230                    syntaxCheckerList.add( entry.getEntry() );
231                }
232            }
233        }
234
235        return syntaxCheckerList;
236    }
237
238
239    /**
240     * {@inheritDoc}
241     */
242    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
243    {
244        List<Entry> normalizerList = new ArrayList<Entry>();
245
246        if ( schemas == null )
247        {
248            return normalizerList;
249        }
250
251        for ( Schema schema : schemas )
252        {
253            String start = getSchemaDirectoryString( schema )
254                + SchemaConstants.NORMALIZERS_PATH + "/" + "m-oid=";
255            String end = "." + LDIF_EXT;
256
257            for ( String resourcePath : RESOURCE_MAP.keySet() )
258            {
259                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
260                {
261                    URL resource = getResource( resourcePath, "normalizer LDIF file" );
262                    LdifReader reader = new LdifReader( resource.openStream() );
263                    LdifEntry entry = reader.next();
264                    reader.close();
265
266                    normalizerList.add( entry.getEntry() );
267                }
268            }
269        }
270
271        return normalizerList;
272    }
273
274
275    /**
276     * {@inheritDoc}
277     */
278    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
279    {
280        List<Entry> matchingRuleList = new ArrayList<Entry>();
281
282        if ( schemas == null )
283        {
284            return matchingRuleList;
285        }
286
287        for ( Schema schema : schemas )
288        {
289            String start = getSchemaDirectoryString( schema )
290                + SchemaConstants.MATCHING_RULES_PATH + "/" + "m-oid=";
291            String end = "." + LDIF_EXT;
292
293            for ( String resourcePath : RESOURCE_MAP.keySet() )
294            {
295                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
296                {
297                    URL resource = getResource( resourcePath, "matchingRules LDIF file" );
298                    LdifReader reader = new LdifReader( resource.openStream() );
299                    LdifEntry entry = reader.next();
300                    reader.close();
301
302                    matchingRuleList.add( entry.getEntry() );
303                }
304            }
305        }
306
307        return matchingRuleList;
308    }
309
310
311    /**
312     * {@inheritDoc}
313     */
314    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
315    {
316        List<Entry> syntaxList = new ArrayList<Entry>();
317
318        if ( schemas == null )
319        {
320            return syntaxList;
321        }
322
323        for ( Schema schema : schemas )
324        {
325            String start = getSchemaDirectoryString( schema )
326                + SchemaConstants.SYNTAXES_PATH + "/" + "m-oid=";
327            String end = "." + LDIF_EXT;
328
329            for ( String resourcePath : RESOURCE_MAP.keySet() )
330            {
331                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
332                {
333                    URL resource = getResource( resourcePath, "syntax LDIF file" );
334                    LdifReader reader = new LdifReader( resource.openStream() );
335                    LdifEntry entry = reader.next();
336                    reader.close();
337
338                    syntaxList.add( entry.getEntry() );
339                }
340            }
341        }
342
343        return syntaxList;
344    }
345
346
347    /**
348     * {@inheritDoc}
349     */
350    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
351    {
352        List<Entry> attributeTypeList = new ArrayList<Entry>();
353
354        if ( schemas == null )
355        {
356            return attributeTypeList;
357        }
358
359        for ( Schema schema : schemas )
360        {
361            // check that the attributeTypes directory exists for the schema
362            String start = getSchemaDirectoryString( schema )
363                + SchemaConstants.ATTRIBUTE_TYPES_PATH + "/" + "m-oid=";
364            String end = "." + LDIF_EXT;
365
366            // get list of attributeType LDIF schema files in attributeTypes
367            for ( String resourcePath : RESOURCE_MAP.keySet() )
368            {
369                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
370                {
371                    URL resource = getResource( resourcePath, "attributeType LDIF file" );
372                    LdifReader reader = new LdifReader( resource.openStream() );
373                    LdifEntry entry = reader.next();
374                    reader.close();
375
376                    attributeTypeList.add( entry.getEntry() );
377                }
378            }
379        }
380
381        return attributeTypeList;
382    }
383
384
385    /**
386     * {@inheritDoc}
387     */
388    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
389    {
390        List<Entry> matchingRuleUseList = new ArrayList<Entry>();
391
392        if ( schemas == null )
393        {
394            return matchingRuleUseList;
395        }
396
397        for ( Schema schema : schemas )
398        {
399            String start = getSchemaDirectoryString( schema )
400                + SchemaConstants.MATCHING_RULE_USE_PATH + "/" + "m-oid=";
401            String end = "." + LDIF_EXT;
402
403            for ( String resourcePath : RESOURCE_MAP.keySet() )
404            {
405                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
406                {
407                    URL resource = getResource( resourcePath, "matchingRuleUse LDIF file" );
408                    LdifReader reader = new LdifReader( resource.openStream() );
409                    LdifEntry entry = reader.next();
410                    reader.close();
411
412                    matchingRuleUseList.add( entry.getEntry() );
413                }
414            }
415        }
416
417        return matchingRuleUseList;
418    }
419
420
421    /**
422     * {@inheritDoc}
423     */
424    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
425    {
426        List<Entry> nameFormList = new ArrayList<Entry>();
427
428        if ( schemas == null )
429        {
430            return nameFormList;
431        }
432
433        for ( Schema schema : schemas )
434        {
435            String start = getSchemaDirectoryString( schema )
436                + SchemaConstants.NAME_FORMS_PATH + "/" + "m-oid=";
437            String end = "." + LDIF_EXT;
438
439            for ( String resourcePath : RESOURCE_MAP.keySet() )
440            {
441                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
442                {
443                    URL resource = getResource( resourcePath, "nameForm LDIF file" );
444                    LdifReader reader = new LdifReader( resource.openStream() );
445                    LdifEntry entry = reader.next();
446                    reader.close();
447
448                    nameFormList.add( entry.getEntry() );
449                }
450            }
451        }
452
453        return nameFormList;
454    }
455
456
457    /**
458     * {@inheritDoc}
459     */
460    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
461    {
462        List<Entry> ditContentRulesList = new ArrayList<Entry>();
463
464        if ( schemas == null )
465        {
466            return ditContentRulesList;
467        }
468
469        for ( Schema schema : schemas )
470        {
471            String start = getSchemaDirectoryString( schema )
472                + SchemaConstants.DIT_CONTENT_RULES_PATH + "/" + "m-oid=";
473            String end = "." + LDIF_EXT;
474
475            for ( String resourcePath : RESOURCE_MAP.keySet() )
476            {
477                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
478                {
479                    URL resource = getResource( resourcePath, "ditContentRule LDIF file" );
480                    LdifReader reader = new LdifReader( resource.openStream() );
481                    LdifEntry entry = reader.next();
482                    reader.close();
483
484                    ditContentRulesList.add( entry.getEntry() );
485                }
486            }
487        }
488
489        return ditContentRulesList;
490    }
491
492
493    /**
494     * {@inheritDoc}
495     */
496    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
497    {
498        List<Entry> ditStructureRuleList = new ArrayList<Entry>();
499
500        if ( schemas == null )
501        {
502            return ditStructureRuleList;
503        }
504
505        for ( Schema schema : schemas )
506        {
507            String start = getSchemaDirectoryString( schema )
508                + SchemaConstants.DIT_STRUCTURE_RULES_PATH + "/" + "m-oid=";
509            String end = "." + LDIF_EXT;
510
511            for ( String resourcePath : RESOURCE_MAP.keySet() )
512            {
513                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
514                {
515                    URL resource = getResource( resourcePath, "ditStructureRule LDIF file" );
516                    LdifReader reader = new LdifReader( resource.openStream() );
517                    LdifEntry entry = reader.next();
518                    reader.close();
519
520                    ditStructureRuleList.add( entry.getEntry() );
521                }
522            }
523        }
524
525        return ditStructureRuleList;
526    }
527
528
529    /**
530     * {@inheritDoc}
531     */
532    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
533    {
534        List<Entry> objectClassList = new ArrayList<Entry>();
535
536        if ( schemas == null )
537        {
538            return objectClassList;
539        }
540
541        for ( Schema schema : schemas )
542        {
543            // get objectClasses directory, check if exists, return if not
544            String start = getSchemaDirectoryString( schema )
545                + SchemaConstants.OBJECT_CLASSES_PATH + "/" + "m-oid=";
546            String end = "." + LDIF_EXT;
547
548            for ( String resourcePath : RESOURCE_MAP.keySet() )
549            {
550                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
551                {
552                    URL resource = getResource( resourcePath, "objectClass LDIF file" );
553                    LdifReader reader = new LdifReader( resource.openStream() );
554                    LdifEntry entry = reader.next();
555                    reader.close();
556
557                    objectClassList.add( entry.getEntry() );
558                }
559            }
560        }
561
562        return objectClassList;
563    }
564}