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
021package org.apache.directory.api.ldap.schemaloader;
022
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.net.URL;
027import java.util.ArrayList;
028import java.util.HashMap;
029import java.util.List;
030import java.util.Map;
031import java.util.regex.Pattern;
032
033import org.apache.directory.api.ldap.model.entry.Entry;
034import org.apache.directory.api.ldap.model.exception.LdapException;
035import org.apache.directory.api.ldap.model.ldif.LdifEntry;
036import org.apache.directory.api.ldap.model.ldif.LdifReader;
037import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
038import org.apache.directory.api.ldap.model.schema.registries.Schema;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042
043/**
044 * A schema loader based on a single monolithic ldif file containing all the schema partition elements
045 * 
046 * Performs better than any other existing LDIF schema loaders. NOT DOCUMENTED atm
047 * 
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 */
050public class SingleLdifSchemaLoader extends AbstractSchemaLoader
051{
052    /** 
053     * Pattern for start of schema Dn.
054     * java.util.regex.Pattern is immutable so only one instance is needed for all uses.
055     */
056    private static final Pattern SCHEMA_START_PATTERN = Pattern
057        .compile( "cn\\s*=\\s*[a-z0-9-_]*\\s*,\\s*ou\\s*=\\s*schema" );
058
059    /** The logger. */
060    private static final Logger LOG = LoggerFactory.getLogger( SingleLdifSchemaLoader.class );
061
062    /** The schema object Rdn attribute types. */
063    private String[] schemaObjectTypeRdns = new String[]
064        { "attributetypes", "comparators", "ditContentRules", "ditStructureRules", "matchingRules", "matchingRuleUse",
065            "nameForms", "normalizers", "objectClasses", "syntaxes", "syntaxCheckers" };
066
067    /** The map containing ... */
068    private Map<String, Map<String, List<Entry>>> scObjEntryMap = new HashMap<String, Map<String, List<Entry>>>();
069
070
071    /**
072     * Instantiates a new single LDIF schema loader.
073     */
074    public SingleLdifSchemaLoader()
075    {
076        try
077        {
078            URL resource = getClass().getClassLoader().getResource( "schema-all.ldif" );
079
080            LOG.debug( "URL of the all schema ldif file {}", resource );
081
082            for ( String s : schemaObjectTypeRdns )
083            {
084                scObjEntryMap.put( s, new HashMap<String, List<Entry>>() );
085            }
086
087            InputStream in = resource.openStream();
088
089            initializeSchemas( in );
090        }
091        catch ( Exception e )
092        {
093            throw new RuntimeException( e );
094        }
095    }
096
097
098    private void initializeSchemas( InputStream in ) throws Exception
099    {
100        LdifReader ldifReader = new LdifReader( in );
101
102        Schema currentSchema = null;
103
104        while ( ldifReader.hasNext() )
105        {
106            LdifEntry ldifEntry = ldifReader.next();
107            String dn = ldifEntry.getDn().getName();
108
109            if ( SCHEMA_START_PATTERN.matcher( dn ).matches() )
110            {
111                Schema schema = getSchema( ldifEntry.getEntry() );
112                schemaMap.put( schema.getSchemaName(), schema );
113                currentSchema = schema;
114            }
115            else
116            {
117                loadSchemaObject( currentSchema.getSchemaName(), ldifEntry );
118            }
119        }
120
121        ldifReader.close();
122    }
123
124
125    private void loadSchemaObject( String schemaName, LdifEntry ldifEntry ) throws Exception
126    {
127        for ( String scObjTypeRdn : schemaObjectTypeRdns )
128        {
129            Pattern regex = Pattern.compile( "m-oid\\s*=\\s*[0-9\\.]*\\s*" + ",\\s*ou\\s*=\\s*" + scObjTypeRdn
130                + "\\s*,\\s*cn\\s*=\\s*" + schemaName
131                + "\\s*,\\s*ou=schema\\s*", Pattern.CASE_INSENSITIVE );
132
133            String dn = ldifEntry.getDn().getName();
134
135            if ( regex.matcher( dn ).matches() )
136            {
137                Map<String, List<Entry>> m = scObjEntryMap.get( scObjTypeRdn );
138                List<Entry> entryList = m.get( schemaName );
139                if ( entryList == null )
140                {
141                    entryList = new ArrayList<Entry>();
142                    entryList.add( ldifEntry.getEntry() );
143                    m.put( schemaName, entryList );
144                }
145                else
146                {
147                    entryList.add( ldifEntry.getEntry() );
148                }
149
150                break;
151            }
152        }
153    }
154
155
156    private List<Entry> loadSchemaObjects( String schemaObjectType, Schema... schemas ) throws LdapException,
157        IOException
158    {
159        Map<String, List<Entry>> m = scObjEntryMap.get( schemaObjectType );
160        List<Entry> atList = new ArrayList<Entry>();
161
162        for ( Schema s : schemas )
163        {
164            List<Entry> preLoaded = m.get( s.getSchemaName() );
165            if ( preLoaded != null )
166            {
167                atList.addAll( preLoaded );
168            }
169        }
170
171        return atList;
172    }
173
174
175    /**
176     * {@inheritDoc}
177     */
178    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
179    {
180        return loadSchemaObjects( "attributetypes", schemas );
181    }
182
183
184    /**
185     * {@inheritDoc}
186     */
187    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
188    {
189        return loadSchemaObjects( "comparators", schemas );
190    }
191
192
193    /**
194     * {@inheritDoc}
195     */
196    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
197    {
198        return loadSchemaObjects( "ditContentRules", schemas );
199    }
200
201
202    /**
203     * {@inheritDoc}
204     */
205    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
206    {
207        return loadSchemaObjects( "ditStructureRules", schemas );
208    }
209
210
211    /**
212     * {@inheritDoc}
213     */
214    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
215    {
216        return loadSchemaObjects( "matchingRules", schemas );
217    }
218
219
220    /**
221     * {@inheritDoc}
222     */
223    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
224    {
225        return loadSchemaObjects( "matchingRuleUse", schemas );
226    }
227
228
229    /**
230     * {@inheritDoc}
231     */
232    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
233    {
234        return loadSchemaObjects( "nameForms", schemas );
235    }
236
237
238    /**
239     * {@inheritDoc}
240     */
241    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
242    {
243        return loadSchemaObjects( "normalizers", schemas );
244    }
245
246
247    /**
248     * {@inheritDoc}
249     */
250    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
251    {
252        return loadSchemaObjects( "objectClasses", schemas );
253    }
254
255
256    /**
257     * {@inheritDoc}
258     */
259    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
260    {
261        return loadSchemaObjects( "syntaxes", schemas );
262    }
263
264
265    /**
266     * {@inheritDoc}
267     */
268    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
269    {
270        return loadSchemaObjects( "syntaxCheckers", schemas );
271    }
272
273}
274
275class SchemaMarker
276{
277    /** The start marker. */
278    private int start;
279
280    /** The end marker. */
281    private int end;
282
283
284    public SchemaMarker( int start )
285    {
286        this.start = start;
287    }
288
289
290    public void setEnd( int end )
291    {
292        this.end = end;
293    }
294
295
296    public int getStart()
297    {
298        return start;
299    }
300
301
302    public int getEnd()
303    {
304        return end;
305    }
306}