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.server.core.schema;
021
022
023import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
024import org.apache.directory.api.ldap.model.constants.SchemaConstants;
025import org.apache.directory.api.ldap.model.entry.DefaultEntry;
026import org.apache.directory.api.ldap.model.entry.Entry;
027import org.apache.directory.api.ldap.model.exception.LdapException;
028import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
029import org.apache.directory.api.ldap.model.name.Dn;
030import org.apache.directory.api.ldap.model.schema.AttributeType;
031import org.apache.directory.api.ldap.model.schema.AttributesFactory;
032import org.apache.directory.api.ldap.model.schema.DitContentRule;
033import org.apache.directory.api.ldap.model.schema.DitStructureRule;
034import org.apache.directory.api.ldap.model.schema.LdapSyntax;
035import org.apache.directory.api.ldap.model.schema.MatchingRule;
036import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
037import org.apache.directory.api.ldap.model.schema.NameForm;
038import org.apache.directory.api.ldap.model.schema.ObjectClass;
039import org.apache.directory.api.ldap.model.schema.SchemaManager;
040import org.apache.directory.api.ldap.model.schema.SchemaObject;
041import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
042import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
043import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
044import org.apache.directory.api.ldap.model.schema.registries.Schema;
045import org.apache.directory.api.util.Base64;
046import org.apache.directory.server.core.api.DnFactory;
047import org.apache.directory.server.core.api.interceptor.Interceptor;
048import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
049import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
050import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
051import org.apache.directory.server.core.api.partition.Partition;
052
053
054/**
055 * Responsible for translating modify operations on the subschemaSubentry into
056 * operations against entries within the schema partition.
057 *
058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
059 */
060public class SchemaSubentryModifier
061{
062    private AttributesFactory factory = new AttributesFactory();
063
064    /** The server schemaManager */
065    private SchemaManager schemaManager;
066
067    /** The Dn factory */
068    private DnFactory dnFactory;
069
070
071    /**
072     * 
073     * Creates a new instance of SchemaSubentryModifier.
074     *
075     * @param schemaManager The server schemaManager
076     * @param dnFactory The Dn factory
077     */
078    public SchemaSubentryModifier( SchemaManager schemaManager, DnFactory dnFactory )
079    {
080        this.schemaManager = schemaManager;
081        this.dnFactory = dnFactory;
082    }
083
084
085    private Dn getDn( SchemaObject obj ) throws LdapInvalidDnException
086    {
087        StringBuilder buf = new StringBuilder();
088        buf.append( "m-oid=" ).append( obj.getOid() ).append( ",ou=" );
089
090        if ( obj instanceof LdapSyntax )
091        {
092            buf.append( SchemaConstants.SYNTAXES );
093        }
094        else if ( obj instanceof MatchingRule )
095        {
096            buf.append( SchemaConstants.MATCHING_RULES_AT );
097        }
098        else if ( obj instanceof AttributeType )
099        {
100            buf.append( SchemaConstants.ATTRIBUTE_TYPES_AT );
101        }
102        else if ( obj instanceof ObjectClass )
103        {
104            buf.append( SchemaConstants.OBJECT_CLASSES_AT );
105        }
106        else if ( obj instanceof MatchingRuleUse )
107        {
108            buf.append( SchemaConstants.MATCHING_RULE_USE_AT );
109        }
110        else if ( obj instanceof DitStructureRule )
111        {
112            buf.append( SchemaConstants.DIT_STRUCTURE_RULES_AT );
113        }
114        else if ( obj instanceof DitContentRule )
115        {
116            buf.append( SchemaConstants.DIT_CONTENT_RULES_AT );
117        }
118        else if ( obj instanceof NameForm )
119        {
120            buf.append( SchemaConstants.NAME_FORMS_AT );
121        }
122
123        buf.append( ",cn=" ).append( obj.getSchemaName() ).append( ",ou=schema" );
124        return dnFactory.create( buf.toString() );
125    }
126
127
128    public void add( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
129        LdapComparatorDescription comparatorDescription ) throws LdapException
130    {
131        String schemaName = getSchema( comparatorDescription );
132        Dn dn = dnFactory.create(
133            "m-oid=" + comparatorDescription.getOid(),
134            SchemaConstants.COMPARATORS_PATH,
135            "cn=" + schemaName,
136            SchemaConstants.OU_SCHEMA );
137
138        Entry entry = getEntry( dn, comparatorDescription );
139        
140        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
141
142        AddOperationContext addContext = new AddOperationContext( modifyContext.getSession(), entry );
143        addContext.setCurrentInterceptor( position );
144        addContext.setPartition( partition );
145        addContext.setTransaction( modifyContext.getTransaction() );
146
147        nextInterceptor.add( addContext );
148    }
149
150
151    public void add( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
152        NormalizerDescription normalizerDescription ) throws LdapException
153    {
154        String schemaName = getSchema( normalizerDescription );
155        Dn dn = dnFactory.create(
156            "m-oid=" + normalizerDescription.getOid(),
157            SchemaConstants.NORMALIZERS_PATH,
158            "cn=" + schemaName,
159            SchemaConstants.OU_SCHEMA );
160
161        Entry entry = getEntry( dn, normalizerDescription );
162
163        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
164
165        AddOperationContext addContext = new AddOperationContext( modifyContext.getSession(), entry );
166        addContext.setCurrentInterceptor( position );
167        addContext.setPartition( partition );
168        addContext.setTransaction( modifyContext.getTransaction() );
169
170        nextInterceptor.add( addContext );
171    }
172
173
174    public void add( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
175        SyntaxCheckerDescription syntaxCheckerDescription ) throws LdapException
176    {
177        String schemaName = getSchema( syntaxCheckerDescription );
178        Dn dn = dnFactory.create(
179            "m-oid=" + syntaxCheckerDescription.getOid(),
180            SchemaConstants.SYNTAX_CHECKERS_PATH,
181            "cn=" + schemaName,
182            SchemaConstants.OU_SCHEMA );
183
184        Entry entry = getEntry( dn, syntaxCheckerDescription );
185
186        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
187
188        AddOperationContext addContext = new AddOperationContext( modifyContext.getSession(), entry );
189        addContext.setCurrentInterceptor( position );
190        addContext.setPartition( partition );
191        addContext.setTransaction( modifyContext.getTransaction() );
192
193        nextInterceptor.add( addContext );
194    }
195
196
197    public void addSchemaObject( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
198        SchemaObject obj ) throws LdapException
199    {
200        Schema schema = schemaManager.getLoadedSchema( obj.getSchemaName() );
201        Dn dn = getDn( obj );
202        Entry entry = factory.getAttributes( obj, schema, schemaManager );
203        entry.setDn( dn );
204
205        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
206
207        AddOperationContext addContext = new AddOperationContext( modifyContext.getSession(), entry );
208        addContext.setCurrentInterceptor( position );
209        addContext.setPartition( partition );
210        addContext.setTransaction( modifyContext.getTransaction() );
211
212        nextInterceptor.add( addContext );
213    }
214
215
216    public void deleteSchemaObject( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
217        SchemaObject obj ) throws LdapException
218    {
219        Dn dn = getDn( obj );
220
221        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
222
223        DeleteOperationContext deleteContext = new DeleteOperationContext( modifyContext.getSession(), dn );
224        deleteContext.setEntry( modifyContext.getSession().lookup( dn ) );
225        deleteContext.setCurrentInterceptor( position );
226        deleteContext.setPartition( partition );
227        deleteContext.setTransaction( modifyContext.getTransaction() );
228
229        nextInterceptor.delete( deleteContext );
230    }
231
232
233    public void delete( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
234        NormalizerDescription normalizerDescription ) throws LdapException
235    {
236        String schemaName = getSchema( normalizerDescription );
237        Dn dn = dnFactory.create(
238            "m-oid=" + normalizerDescription.getOid(),
239            SchemaConstants.NORMALIZERS_PATH,
240            "cn=" + schemaName,
241            SchemaConstants.OU_SCHEMA );
242
243        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
244
245        DeleteOperationContext deleteContext = new DeleteOperationContext( modifyContext.getSession(), dn );
246        deleteContext.setEntry( modifyContext.getSession().lookup( dn ) );
247        deleteContext.setCurrentInterceptor( position );
248        deleteContext.setPartition( partition );
249        deleteContext.setTransaction( modifyContext.getTransaction() );
250
251        nextInterceptor.delete( deleteContext );
252    }
253
254
255    public void delete( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
256        SyntaxCheckerDescription syntaxCheckerDescription ) throws LdapException
257    {
258        String schemaName = getSchema( syntaxCheckerDescription );
259        Dn dn = dnFactory.create(
260            "m-oid=" + syntaxCheckerDescription.getOid(),
261            SchemaConstants.SYNTAX_CHECKERS_PATH,
262            "cn=" + schemaName,
263            SchemaConstants.OU_SCHEMA );
264
265        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
266
267        DeleteOperationContext deleteContext = new DeleteOperationContext( modifyContext.getSession(), dn );
268        deleteContext.setEntry( modifyContext.getSession().lookup( dn ) );
269        deleteContext.setCurrentInterceptor( position );
270        deleteContext.setPartition( partition );
271        deleteContext.setTransaction( modifyContext.getTransaction() );
272
273        nextInterceptor.delete( deleteContext );
274    }
275
276
277    public void delete( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
278        LdapComparatorDescription comparatorDescription ) throws LdapException
279    {
280        String schemaName = getSchema( comparatorDescription );
281        Dn dn = dnFactory.create(
282            "m-oid=" + comparatorDescription.getOid(),
283            SchemaConstants.COMPARATORS_PATH,
284            "cn=" + schemaName,
285            SchemaConstants.OU_SCHEMA );
286
287        Partition partition = modifyContext.getSession().getDirectoryService().getPartitionNexus().getPartition( dn );
288
289        DeleteOperationContext deleteContext = new DeleteOperationContext( modifyContext.getSession(), dn );
290        deleteContext.setEntry( modifyContext.getSession().lookup( dn ) );
291        deleteContext.setCurrentInterceptor( position );
292        deleteContext.setPartition( partition );
293        deleteContext.setTransaction( modifyContext.getTransaction() );
294
295        nextInterceptor.delete( deleteContext );
296    }
297
298
299    private Entry getEntry( Dn dn, LdapComparatorDescription comparatorDescription )
300    {
301        Entry entry = new DefaultEntry( schemaManager, dn );
302
303        entry.put( SchemaConstants.OBJECT_CLASS_AT,
304            SchemaConstants.TOP_OC,
305            MetaSchemaConstants.META_TOP_OC,
306            MetaSchemaConstants.META_COMPARATOR_OC );
307
308        entry.put( MetaSchemaConstants.M_OID_AT, comparatorDescription.getOid() );
309        entry.put( MetaSchemaConstants.M_FQCN_AT, comparatorDescription.getFqcn() );
310
311        if ( comparatorDescription.getBytecode() != null )
312        {
313            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
314                Base64.decode( comparatorDescription.getBytecode().toCharArray() ) );
315        }
316
317        if ( comparatorDescription.getDescription() != null )
318        {
319            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, comparatorDescription.getDescription() );
320        }
321
322        return entry;
323    }
324
325
326    private Entry getEntry( Dn dn, NormalizerDescription normalizerDescription )
327    {
328        Entry entry = new DefaultEntry( schemaManager, dn );
329
330        entry.put( SchemaConstants.OBJECT_CLASS_AT,
331            SchemaConstants.TOP_OC,
332            MetaSchemaConstants.META_TOP_OC,
333            MetaSchemaConstants.META_NORMALIZER_OC );
334
335        entry.put( MetaSchemaConstants.M_OID_AT, normalizerDescription.getOid() );
336        entry.put( MetaSchemaConstants.M_FQCN_AT, normalizerDescription.getFqcn() );
337
338        if ( normalizerDescription.getBytecode() != null )
339        {
340            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
341                Base64.decode( normalizerDescription.getBytecode().toCharArray() ) );
342        }
343
344        if ( normalizerDescription.getDescription() != null )
345        {
346            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, normalizerDescription.getDescription() );
347        }
348
349        return entry;
350    }
351
352
353    private String getSchema( SchemaObject desc )
354    {
355        if ( desc.getExtensions().containsKey( MetaSchemaConstants.X_SCHEMA_AT ) )
356        {
357            return desc.getExtensions().get( MetaSchemaConstants.X_SCHEMA_AT ).get( 0 );
358        }
359
360        return MetaSchemaConstants.SCHEMA_OTHER;
361    }
362
363
364    private Entry getEntry( Dn dn, SyntaxCheckerDescription syntaxCheckerDescription )
365    {
366        Entry entry = new DefaultEntry( schemaManager, dn );
367
368        entry.put( SchemaConstants.OBJECT_CLASS_AT,
369            SchemaConstants.TOP_OC,
370            MetaSchemaConstants.META_TOP_OC,
371            MetaSchemaConstants.META_SYNTAX_CHECKER_OC );
372
373        entry.put( MetaSchemaConstants.M_OID_AT, syntaxCheckerDescription.getOid() );
374        entry.put( MetaSchemaConstants.M_FQCN_AT, syntaxCheckerDescription.getFqcn() );
375
376        if ( syntaxCheckerDescription.getBytecode() != null )
377        {
378            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
379                Base64.decode( syntaxCheckerDescription.getBytecode().toCharArray() ) );
380        }
381
382        if ( syntaxCheckerDescription.getDescription() != null )
383        {
384            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, syntaxCheckerDescription.getDescription() );
385        }
386
387        return entry;
388    }
389}