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