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.lang.reflect.Constructor;
024import java.lang.reflect.InvocationTargetException;
025import java.lang.reflect.Method;
026import java.security.AccessController;
027import java.security.PrivilegedAction;
028import java.util.ArrayList;
029import java.util.HashSet;
030import java.util.List;
031import java.util.Set;
032
033import org.apache.directory.api.asn1.util.Oid;
034import org.apache.directory.api.i18n.I18n;
035import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
036import org.apache.directory.api.ldap.model.constants.SchemaConstants;
037import org.apache.directory.api.ldap.model.entry.Attribute;
038import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
039import org.apache.directory.api.ldap.model.entry.Entry;
040import org.apache.directory.api.ldap.model.entry.Value;
041import org.apache.directory.api.ldap.model.exception.LdapException;
042import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
043import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
044import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
045import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
046import org.apache.directory.api.ldap.model.schema.AttributeType;
047import org.apache.directory.api.ldap.model.schema.LdapComparator;
048import org.apache.directory.api.ldap.model.schema.LdapSyntax;
049import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
050import org.apache.directory.api.ldap.model.schema.MatchingRule;
051import org.apache.directory.api.ldap.model.schema.ObjectClass;
052import org.apache.directory.api.ldap.model.schema.Normalizer;
053import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
054import org.apache.directory.api.ldap.model.schema.SchemaManager;
055import org.apache.directory.api.ldap.model.schema.SchemaObject;
056import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
057import org.apache.directory.api.ldap.model.schema.SyntaxChecker.SCBuilder;
058import org.apache.directory.api.ldap.model.schema.UsageEnum;
059import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
060import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
061import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
062import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
063import org.apache.directory.api.ldap.model.schema.registries.Registries;
064import org.apache.directory.api.ldap.model.schema.registries.Schema;
065import org.apache.directory.api.util.Base64;
066import org.apache.directory.api.util.StringConstants;
067import org.apache.directory.api.util.Strings;
068import org.slf4j.Logger;
069import org.slf4j.LoggerFactory;
070
071
072/**
073 * Showing how it's done ...
074 *
075 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
076 */
077public class SchemaEntityFactory implements EntityFactory
078{
079    /** Slf4j logger */
080    private static final Logger LOG = LoggerFactory.getLogger( SchemaEntityFactory.class );
081
082    /** The empty string list. */
083    private static final List<String> EMPTY_LIST = new ArrayList<>();
084
085    /** The empty string array. */
086    private static final String[] EMPTY_ARRAY = new String[]
087        {};
088
089    /** A special ClassLoader that loads a class from the bytecode attribute */
090    private final AttributeClassLoader classLoader;
091
092
093    /**
094     * Instantiates a new schema entity factory.
095     */
096    public SchemaEntityFactory()
097    {
098        this.classLoader = AccessController.doPrivileged( new PrivilegedAction<AttributeClassLoader>()
099        {
100            @Override
101            public AttributeClassLoader run() 
102            {
103                return new AttributeClassLoader();
104            }
105        } );
106    }
107
108
109    /**
110     * Get an OID from an entry. Handles the bad cases (null OID,
111     * not a valid OID, ...)
112     * 
113     * @param entry The entry to process
114     * @param objectType The type of processed SchemaObject
115     * @param strict If we want a strict control of the OID
116     * @return The found OID
117     * @throws LdapInvalidAttributeValueException If the OID is not valid 
118     */
119    private String getOid( Entry entry, String objectType, boolean strict ) throws LdapInvalidAttributeValueException
120    {
121        // The OID
122        Attribute mOid = entry.get( MetaSchemaConstants.M_OID_AT );
123
124        if ( mOid == null )
125        {
126            String msg = I18n.err( I18n.ERR_16011_NULL_ATTRIBUTE, objectType, MetaSchemaConstants.M_OID_AT );
127            
128            if ( LOG.isWarnEnabled() )
129            {
130                LOG.warn( msg );
131            }
132            
133            throw new IllegalArgumentException( msg );
134        }
135
136        String oid = mOid.getString();
137
138        if ( strict && !Oid.isOid( oid ) )
139        {
140            String msg = I18n.err( I18n.ERR_16012_INVALID_COMPARATOR_OID, oid );
141            
142            if ( LOG.isWarnEnabled() )
143            {
144                LOG.warn( msg );
145            }
146            
147            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
148        }
149
150        return oid;
151    }
152
153
154    /**
155     * Get an OID from an entry. Handles the bad cases (null OID,
156     * not a valid OID, ...)
157     * 
158     * @param description The schemaObject description
159     * @param objectType The type of SchemaObject being processed
160     * @return The found OID
161     * @throws LdapInvalidAttributeValueException If the OID is invalid
162     */
163    private String getOid( SchemaObject description, String objectType ) throws LdapInvalidAttributeValueException
164    {
165        // The OID
166        String oid = description.getOid();
167
168        if ( oid == null )
169        {
170            String msg = I18n.err( I18n.ERR_16011_NULL_ATTRIBUTE, objectType, MetaSchemaConstants.M_OID_AT );
171            
172            if ( LOG.isWarnEnabled() )
173            {
174                LOG.warn( msg );
175            }
176            
177            throw new IllegalArgumentException( msg );
178        }
179
180        if ( !Oid.isOid( oid ) )
181        {
182            String msg = I18n.err( I18n.ERR_16012_INVALID_COMPARATOR_OID, oid );
183            
184            if ( LOG.isWarnEnabled() )
185            {
186                LOG.warn( msg );
187            }
188            
189            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
190        }
191
192        return oid;
193    }
194
195
196    /**
197     * Check that the Entry is not null
198     * 
199     * @param entry The entry to check
200     * @param schemaEntity The message to log if the entry is invalid
201     */
202    private void checkEntry( Entry entry, String schemaEntity )
203    {
204        if ( entry == null )
205        {
206            String msg = I18n.err( I18n.ERR_16013_NULL_ENTRY, schemaEntity );
207            
208            if ( LOG.isWarnEnabled() )
209            {
210                LOG.warn( msg );
211            }
212            
213            throw new IllegalArgumentException( msg );
214        }
215    }
216
217
218    /**
219     * Check that the Description is not null
220     * 
221     * @param description description entry to check
222     * @param schemaEntity The message to log if the description is invalid
223     */
224    private void checkDescription( SchemaObject description, String schemaEntity )
225    {
226        if ( description == null )
227        {
228            String msg = I18n.err( I18n.ERR_16014_NULL_SCHEMA_DESC, schemaEntity );
229            
230            if ( LOG.isWarnEnabled() )
231            {
232                LOG.warn( msg );
233            }
234            
235            throw new IllegalArgumentException( msg );
236        }
237    }
238
239
240    /**
241     * Get the schema from its name. Return the Other reference if there
242     * is no schema name. Throws a NPE if the schema is not loaded.
243     * 
244     * @param schemaName The schema name to fetch
245     * @param registries The registries where we get the schema from
246     * @return the found Schema
247     */
248    private Schema getSchema( String schemaName, Registries registries )
249    {
250        if ( Strings.isEmpty( schemaName ) )
251        {
252            schemaName = MetaSchemaConstants.SCHEMA_OTHER;
253        }
254
255        Schema schema = registries.getLoadedSchema( schemaName );
256
257        if ( schema == null )
258        {
259            String msg = I18n.err( I18n.ERR_16015_NON_EXISTENT_SCHEMA, schemaName );
260            LOG.error( msg );
261        }
262
263        return schema;
264    }
265
266
267    /**
268     * {@inheritDoc}
269     */
270    @Override
271    public Schema getSchema( Entry entry ) throws LdapException
272    {
273        String name;
274        String owner;
275        String[] dependencies = EMPTY_ARRAY;
276        boolean isDisabled = false;
277
278        if ( entry == null )
279        {
280            throw new IllegalArgumentException( I18n.err( I18n.ERR_16016_NULL_ENTRY ) );
281        }
282
283        if ( entry.get( SchemaConstants.CN_AT ) == null )
284        {
285            throw new IllegalArgumentException( I18n.err( I18n.ERR_16017_INVALID_CN_AT ) );
286        }
287
288        name = entry.get( SchemaConstants.CN_AT ).getString();
289
290        if ( entry.get( SchemaConstants.CREATORS_NAME_AT ) == null )
291        {
292            throw new IllegalArgumentException( I18n.err( I18n.ERR_16018_INVALID_AT, SchemaConstants.CREATORS_NAME_AT ) );
293        }
294
295        owner = entry.get( SchemaConstants.CREATORS_NAME_AT ).getString();
296
297        if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
298        {
299            String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
300            value = Strings.upperCase( value );
301            isDisabled = "TRUE".equalsIgnoreCase( value );
302        }
303
304        if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
305        {
306            Set<String> depsSet = new HashSet<>();
307            Attribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
308
309            for ( Value value : depsAttr )
310            {
311                depsSet.add( value.getString() );
312            }
313
314            dependencies = depsSet.toArray( EMPTY_ARRAY );
315        }
316
317        return new DefaultSchema( null, name, owner, dependencies, isDisabled );
318    }
319
320
321    /**
322     * Class load a SyntaxChecker instance
323     * 
324     * @param schemaManager The SchemaManager
325     * @param oid The SyntaxChecker OID
326     * @param className The class name associated with the SyntaxChecker
327     * @param byteCode The SyntaxChecker class bytecode
328     * @return The loaded SyntaxChecker
329     * @throws LdapException If the SyntaxChecker cannot be loaded
330     */
331    private SyntaxChecker classLoadSyntaxChecker( SchemaManager schemaManager, String oid, String className,
332        Attribute byteCode ) throws LdapException
333    {
334        // Try to class load the syntaxChecker
335        Class<?> clazz;
336        SyntaxChecker syntaxChecker;
337        String byteCodeStr = StringConstants.EMPTY;
338
339        if ( byteCode == null )
340        {
341            try
342            {
343                clazz = Class.forName( className );
344            }
345            catch ( ClassNotFoundException cnfe )
346            {
347                LOG.error( I18n.err( I18n.ERR_16048_CANNOT_FIND_SC_CTOR, className ) );
348                throw new LdapSchemaException( I18n.err( I18n.ERR_16049_CANNOT_FIND_SC_CLASS, cnfe.getMessage() ) );
349            }
350        }
351        else
352        {
353            classLoader.setAttribute( byteCode );
354            
355            try
356            {
357                clazz = classLoader.loadClass( className );
358            }
359            catch ( ClassNotFoundException cnfe )
360            {
361                LOG.error( I18n.err( I18n.ERR_16050_CANNOT_LOAD_SC_CTOR, className ) );
362                throw new LdapSchemaException( I18n.err( I18n.ERR_16051_CANNOT_LOAD_SC_CLASS, cnfe.getMessage() ) );
363            }
364            
365            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
366        }
367
368        // Create the syntaxChecker instance
369        try
370        {
371            Method builder = clazz.getMethod( "builder", ( Class<?>[] ) null );
372            syntaxChecker = ( SyntaxChecker ) ( ( SCBuilder ) builder.invoke( null, ( Object[] ) null ) ).setOid( oid ).build();
373        }
374        catch ( NoSuchMethodException nsme )
375        {
376            LOG.error( I18n.err( I18n.ERR_16052_CANNOT_INST_SC_CTOR, className ) );
377            throw new LdapSchemaException( I18n.err( I18n.ERR_16053_CANNOT_INST_SC_CLASS, nsme.getMessage() ) );
378        }
379        catch ( InvocationTargetException | IllegalAccessException e )
380        {
381            LOG.error( I18n.err( I18n.ERR_16054_CANNOT_ACCESS_SC_CTOR, className ) );
382            throw new LdapSchemaException( I18n.err( I18n.ERR_16055_CANNOT_ACCESS_SC_CLASS, e.getMessage() ) );
383        }
384
385        // Update the common fields
386        syntaxChecker.setBytecode( byteCodeStr );
387        syntaxChecker.setFqcn( className );
388
389        // Inject the SchemaManager for the comparator who needs it
390        syntaxChecker.setSchemaManager( schemaManager );
391
392        return syntaxChecker;
393    }
394
395
396    /**
397     * {@inheritDoc}
398     */
399    @Override
400    public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
401        String schemaName ) throws LdapException
402    {
403        checkEntry( entry, SchemaConstants.SYNTAX_CHECKER );
404
405        // The SyntaxChecker OID
406        String oid = getOid( entry, SchemaConstants.SYNTAX_CHECKER, schemaManager.isStrict() );
407
408        // Get the schema
409        if ( !schemaManager.isSchemaLoaded( schemaName ) )
410        {
411            // The schema is not loaded. We can't create the requested Normalizer
412            String msg = I18n.err( I18n.ERR_16019_CANNOT_ADD_SC, entry.getDn().getName(), schemaName );
413            
414            if ( LOG.isWarnEnabled() )
415            {
416                LOG.warn( msg );
417            }
418            
419            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
420        }
421
422        Schema schema = getSchema( schemaName, targetRegistries );
423
424        if ( schema == null )
425        {
426            // The schema is disabled. We still have to update the backend
427            if ( LOG.isInfoEnabled() )
428            {
429                LOG.info( I18n.err( I18n.ERR_16020_CANNOT_ADD_SC_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
430            }
431            
432            schema = schemaManager.getLoadedSchema( schemaName );
433        }
434
435        // The FQCN
436        String className = getFqcn( entry, SchemaConstants.SYNTAX_CHECKER );
437
438        // The ByteCode
439        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
440
441        try
442        {
443            // Class load the syntaxChecker
444            SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, className, byteCode );
445
446            // Update the common fields
447            setSchemaObjectProperties( syntaxChecker, entry, schema );
448
449            // return the resulting syntaxChecker
450            return syntaxChecker;
451        }
452        catch ( Exception e )
453        {
454            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
455        }
456    }
457
458
459    /**
460     * {@inheritDoc}
461     */
462    @Override
463    public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager,
464        SyntaxCheckerDescription syntaxCheckerDescription, Registries targetRegistries, String schemaName )
465        throws LdapException
466    {
467        checkDescription( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
468
469        // The Comparator OID
470        String oid = getOid( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
471
472        // Get the schema
473        Schema schema = getSchema( schemaName, targetRegistries );
474
475        if ( schema == null )
476        {
477            // The schema is not loaded. We can't create the requested SyntaxChecker
478            String msg = I18n.err( I18n.ERR_16019_CANNOT_ADD_SC, syntaxCheckerDescription.getName(), schemaName );
479            
480            if ( LOG.isWarnEnabled() )
481            {
482                LOG.warn( msg );
483            }
484            
485            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
486        }
487
488        // The FQCN
489        String fqcn = getFqcn( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
490
491        // get the byteCode
492        Attribute byteCode = getByteCode( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
493
494        // Class load the SyntaxChecker
495        SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, fqcn, byteCode );
496
497        // Update the common fields
498        setSchemaObjectProperties( syntaxChecker, syntaxCheckerDescription, schema );
499
500        return syntaxChecker;
501    }
502
503
504    /**
505     * Class load a comparator instances
506     * 
507     * @param schemaManager The SchemaManager
508     * @param oid The comparator OID
509     * @param className The class name associated with the comparator
510     * @param byteCode The comparator class bytecode
511     * @return The loaded comparator
512     * @throws LdapException If the comparator cannot be loaded
513     */
514    private LdapComparator<?> classLoadComparator( SchemaManager schemaManager, String oid, String className,
515        Attribute byteCode ) throws LdapException
516    {
517        // Try to class load the comparator
518        LdapComparator<?> comparator;
519        Class<?> clazz;
520        String byteCodeStr = StringConstants.EMPTY;
521
522        if ( byteCode == null )
523        {
524            try
525            {
526                clazz = Class.forName( className );
527            }
528            catch ( ClassNotFoundException cnfe )
529            {
530                LOG.error( I18n.err( I18n.ERR_16056_CANNOT_FIND_CMP_CTOR, className ) );
531                throw new LdapSchemaException( I18n.err( I18n.ERR_16057_CANNOT_FIND_CMP_CLASS, cnfe.getMessage() ) );
532            }
533        }
534        else
535        {
536            classLoader.setAttribute( byteCode );
537            
538            try
539            {
540                clazz = classLoader.loadClass( className );
541            }
542            catch ( ClassNotFoundException cnfe )
543            {
544                LOG.error( I18n.err( I18n.ERR_16058_CANNOT_LOAD_CMP_CTOR, className ) );
545                throw new LdapSchemaException( I18n.err( I18n.ERR_16059_CANNOT_LOAD_CMP_CLASS, cnfe.getMessage() ) );
546            }
547
548            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
549        }
550
551        // Create the comparator instance. Either we have a no argument constructor,
552        // or we have one which takes an OID. Lets try the one with an OID argument first
553        try
554        {
555            Constructor<?> constructor = clazz.getConstructor( new Class[]
556                { String.class } );
557            
558            try
559            {
560                comparator = ( LdapComparator<?> ) constructor.newInstance( oid );
561            }
562            catch ( InvocationTargetException ite )
563            {
564                LOG.error( I18n.err( I18n.ERR_16060_CANNOT_INVOKE_CMP_CTOR, className ) );
565                throw new LdapSchemaException( I18n.err( I18n.ERR_16061_CANNOT_INVOKE_CMP_CLASS, ite.getMessage() ) );
566            }
567            catch ( InstantiationException ie )
568            {
569                LOG.error( I18n.err( I18n.ERR_16062_CANNOT_INST_CMP_CTOR_CLASS, className ) );
570                throw new LdapSchemaException( I18n.err( I18n.ERR_16063_CANNOT_INST_CMP_CLASS, ie.getMessage() ) );
571            }
572            catch ( IllegalAccessException ie )
573            {
574                LOG.error( I18n.err( I18n.ERR_16064_CANNOT_ACCESS_CMP_CTOR, className ) );
575                throw new LdapSchemaException( I18n.err( I18n.ERR_16065_CANNOT_ACCESS_CMP_CLASS, ie.getMessage() ) );
576            }
577        }
578        catch ( NoSuchMethodException nsme )
579        {
580            // Ok, let's try with the constructor without argument.
581            // In this case, we will have to check that the OID is the same than
582            // the one we got in the Comparator entry
583            try
584            {
585                clazz.getConstructor();
586            }
587            catch ( NoSuchMethodException nsme2 )
588            {
589                LOG.error( I18n.err( I18n.ERR_16066_CANNOT_FIND_CMP_CTOR_METH_CLASS, className ) );
590                throw new LdapSchemaException( I18n.err( I18n.ERR_16067_CANNOT_FIND_CMP_CTOR_METH, nsme2.getMessage() ) );
591            }
592            
593            try
594            { 
595                comparator = ( LdapComparator<?> ) clazz.newInstance();
596            }
597            catch ( InstantiationException ie )
598            {
599                LOG.error( I18n.err( I18n.ERR_16062_CANNOT_INST_CMP_CTOR_CLASS, className ) );
600                throw new LdapSchemaException( I18n.err( I18n.ERR_16063_CANNOT_INST_CMP_CLASS, ie.getMessage() ) );
601            }
602            catch ( IllegalAccessException iae )
603            {
604                LOG.error( I18n.err( I18n.ERR_16064_CANNOT_ACCESS_CMP_CTOR, className ) );
605                throw new LdapSchemaException( I18n.err( I18n.ERR_16065_CANNOT_ACCESS_CMP_CLASS, iae.getMessage() ) );
606            }
607
608            if ( !comparator.getOid().equals( oid ) )
609            {
610                String msg = I18n.err( I18n.ERR_16021_DIFFERENT_COMPARATOR_OID, oid, comparator.getOid() );
611                throw new LdapInvalidAttributeValueException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg, nsme );
612            }
613        }
614
615        // Update the loadable fields
616        comparator.setBytecode( byteCodeStr );
617        comparator.setFqcn( className );
618
619        // Inject the SchemaManager for the comparator who needs it
620        comparator.setSchemaManager( schemaManager );
621
622        return comparator;
623    }
624
625
626    /**
627     * {@inheritDoc}
628     */
629    @Override
630    public LdapComparator<?> getLdapComparator( SchemaManager schemaManager,
631        LdapComparatorDescription comparatorDescription, Registries targetRegistries, String schemaName )
632        throws LdapException
633    {
634        checkDescription( comparatorDescription, SchemaConstants.COMPARATOR );
635
636        // The Comparator OID
637        String oid = getOid( comparatorDescription, SchemaConstants.COMPARATOR );
638
639        // Get the schema
640        Schema schema = getSchema( schemaName, targetRegistries );
641
642        if ( schema == null )
643        {
644            // The schema is not loaded. We can't create the requested Comparator
645            String msg = I18n.err( I18n.ERR_16022_CANNOT_ADD_CMP, comparatorDescription.getName(), schemaName );
646            
647            if ( LOG.isWarnEnabled() )
648            {
649                LOG.warn( msg );
650            }
651            
652            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
653        }
654
655        // The FQCN
656        String fqcn = getFqcn( comparatorDescription, SchemaConstants.COMPARATOR );
657
658        // get the byteCode
659        Attribute byteCode = getByteCode( comparatorDescription, SchemaConstants.COMPARATOR );
660
661        // Class load the comparator
662        LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode );
663
664        // Update the common fields
665        setSchemaObjectProperties( comparator, comparatorDescription, schema );
666
667        return comparator;
668    }
669
670
671    /**
672     * {@inheritDoc}
673     */
674    @Override
675    public LdapComparator<?> getLdapComparator( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
676        String schemaName ) throws LdapException
677    {
678        checkEntry( entry, SchemaConstants.COMPARATOR );
679
680        // The Comparator OID
681        String oid = getOid( entry, SchemaConstants.COMPARATOR, schemaManager.isStrict() );
682
683        // Get the schema
684        if ( !schemaManager.isSchemaLoaded( schemaName ) )
685        {
686            // The schema is not loaded. We can't create the requested Comparator
687            String msg = I18n.err( I18n.ERR_16022_CANNOT_ADD_CMP, entry.getDn().getName(), schemaName );
688            
689            if ( LOG.isWarnEnabled() )
690            {
691                LOG.warn( msg );
692            }
693            
694            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
695        }
696
697        Schema schema = getSchema( schemaName, targetRegistries );
698
699        if ( schema == null )
700        {
701            // The schema is disabled. We still have to update the backend
702            if ( LOG.isInfoEnabled() )
703            {
704                LOG.info( I18n.err( I18n.ERR_16023_CANNOT_ADD_CMP_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
705            }
706            
707            schema = schemaManager.getLoadedSchema( schemaName );
708        }
709
710        // The FQCN
711        String fqcn = getFqcn( entry, SchemaConstants.COMPARATOR );
712
713        // The ByteCode
714        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
715
716        try
717        {
718            // Class load the comparator
719            LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode );
720
721            // Update the common fields
722            setSchemaObjectProperties( comparator, entry, schema );
723
724            // return the resulting comparator
725            return comparator;
726        }
727        catch ( Exception e )
728        {
729            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
730        }
731    }
732
733
734    /**
735     * Class load a normalizer instances
736     * 
737     * @param schemaManager The SchemaManager
738     * @param oid The normalizer OID
739     * @param className The class name associated with the normalizer
740     * @param byteCode The normalizer class bytecode
741     * @return The loaded normalizer
742     * @throws LdapException If the normalizer cannot be loaded
743     */
744    private Normalizer classLoadNormalizer( SchemaManager schemaManager, String oid, String className,
745        Attribute byteCode ) throws LdapException
746    {
747        // Try to class load the normalizer
748        Class<?> clazz;
749        Normalizer normalizer;
750        String byteCodeStr = StringConstants.EMPTY;
751
752        if ( byteCode == null )
753        {
754            try
755            {  
756                clazz = Class.forName( className );
757            }
758            catch ( ClassNotFoundException cnfe )
759            {
760                LOG.error( I18n.err( I18n.ERR_16068_CANNOT_FIND_NORM_CTOR, className ) );
761                throw new LdapSchemaException( I18n.err( I18n.ERR_16069_CANNOT_FIND_NORM_CLASS, cnfe.getMessage() ) );
762            }
763        }
764        else
765        {
766            classLoader.setAttribute( byteCode );
767            
768            try
769            {
770                clazz = classLoader.loadClass( className );
771            }
772            catch ( ClassNotFoundException cnfe )
773            {
774                LOG.error( I18n.err( I18n.ERR_16070_CANNOT_LOAD_NORM_CTOR, className ) );
775                throw new LdapSchemaException( I18n.err( I18n.ERR_16071_CANNOT_LOAD_NORM_CLASS, cnfe.getMessage() ) );
776            }
777
778            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
779        }
780
781        // Create the normalizer instance
782        try
783        { 
784            normalizer = ( Normalizer ) clazz.newInstance();
785        }
786        catch ( InstantiationException ie )
787        {
788            LOG.error( I18n.err( I18n.ERR_16072_CANNOT_INST_NORM_CTOR_CLASS, className ) );
789            throw new LdapSchemaException( I18n.err( I18n.ERR_16073_CANNOT_INST_NORM_CLASS, ie.getMessage() ) );
790        }
791        catch ( IllegalAccessException iae )
792        {
793            LOG.error( I18n.err( I18n.ERR_16074_CANNOT_ACCESS_NORM_CTOR_CLASS, className ) );
794            throw new LdapSchemaException( I18n.err( I18n.ERR_16075_CANNOT_ACCESS_NORM_CTOR, iae.getMessage() ) );
795        }
796
797        // Update the common fields
798        normalizer.setBytecode( byteCodeStr );
799        normalizer.setFqcn( className );
800
801        // Inject the new OID, as the loaded normalizer might have its own
802        normalizer.setOid( oid );
803
804        // Inject the SchemaManager for the normalizer who needs it
805        normalizer.setSchemaManager( schemaManager );
806
807        return normalizer;
808    }
809
810
811    /**
812     * {@inheritDoc}
813     */
814    @Override
815    public Normalizer getNormalizer( SchemaManager schemaManager, NormalizerDescription normalizerDescription,
816        Registries targetRegistries, String schemaName ) throws LdapException
817    {
818        checkDescription( normalizerDescription, SchemaConstants.NORMALIZER );
819
820        // The Comparator OID
821        String oid = getOid( normalizerDescription, SchemaConstants.NORMALIZER );
822
823        // Get the schema
824        Schema schema = getSchema( schemaName, targetRegistries );
825
826        if ( schema == null )
827        {
828            // The schema is not loaded. We can't create the requested Normalizer
829            String msg = I18n.err( I18n.ERR_16024_CANNOT_ADD_NORMALIZER, normalizerDescription.getName(), schemaName );
830            
831            if ( LOG.isWarnEnabled() )
832            {
833                LOG.warn( msg );
834            }
835            
836            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
837        }
838
839        // The FQCN
840        String fqcn = getFqcn( normalizerDescription, SchemaConstants.NORMALIZER );
841
842        // get the byteCode
843        Attribute byteCode = getByteCode( normalizerDescription, SchemaConstants.NORMALIZER );
844
845        // Class load the normalizer
846        Normalizer normalizer = classLoadNormalizer( schemaManager, oid, fqcn, byteCode );
847
848        // Update the common fields
849        setSchemaObjectProperties( normalizer, normalizerDescription, schema );
850
851        return normalizer;
852    }
853
854
855    /**
856     * {@inheritDoc}
857     */
858    @Override
859    public Normalizer getNormalizer( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
860        String schemaName ) throws LdapException
861    {
862        checkEntry( entry, SchemaConstants.NORMALIZER );
863
864        // The Normalizer OID
865        String oid = getOid( entry, SchemaConstants.NORMALIZER, schemaManager.isStrict() );
866
867        // Get the schema
868        if ( !schemaManager.isSchemaLoaded( schemaName ) )
869        {
870            // The schema is not loaded. We can't create the requested Normalizer
871            String msg = I18n.err( I18n.ERR_16024_CANNOT_ADD_NORMALIZER, entry.getDn().getName(), schemaName );
872            
873            if ( LOG.isWarnEnabled() )
874            {
875                LOG.warn( msg );
876            }
877            
878            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
879        }
880
881        Schema schema = getSchema( schemaName, targetRegistries );
882
883        if ( schema == null )
884        {
885            // The schema is disabled. We still have to update the backend
886            if ( LOG.isInfoEnabled() )
887            {
888                LOG.info( I18n.err( I18n.ERR_16025_CANNOT_ADD_NORMALIZER_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
889            }
890            
891            schema = schemaManager.getLoadedSchema( schemaName );
892        }
893
894        // The FQCN
895        String className = getFqcn( entry, SchemaConstants.NORMALIZER );
896
897        // The ByteCode
898        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
899
900        try
901        {
902            // Class load the Normalizer
903            Normalizer normalizer = classLoadNormalizer( schemaManager, oid, className, byteCode );
904
905            // Update the common fields
906            setSchemaObjectProperties( normalizer, entry, schema );
907
908            // return the resulting Normalizer
909            return normalizer;
910        }
911        catch ( Exception e )
912        {
913            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
914        }
915    }
916
917
918    /**
919     * {@inheritDoc}
920     * @throws LdapInvalidAttributeValueException If the Syntax does not exist
921     * @throws LdapUnwillingToPerformException If the schema is not loaded
922     */
923    @Override
924    public LdapSyntax getSyntax( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
925        String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
926    {
927        checkEntry( entry, SchemaConstants.SYNTAX );
928
929        // The Syntax OID
930        String oid = getOid( entry, SchemaConstants.SYNTAX, schemaManager.isStrict() );
931
932        // Get the schema
933        if ( !schemaManager.isSchemaLoaded( schemaName ) )
934        {
935            // The schema is not loaded. We can't create the requested Syntax
936            String msg = I18n.err( I18n.ERR_16026_CANNOT_ADD_SYNTAX, entry.getDn().getName(), schemaName );
937            
938            if ( LOG.isWarnEnabled() )
939            {
940                LOG.warn( msg );
941            }
942            
943            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
944        }
945
946        Schema schema = getSchema( schemaName, targetRegistries );
947
948        if ( schema == null )
949        {
950            // The schema is disabled. We still have to update the backend
951            if ( LOG.isInfoEnabled() )
952            {
953                LOG.info( I18n.err( I18n.ERR_16027_CANNOT_ADD_SYNTAX_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
954            }
955            
956            schema = schemaManager.getLoadedSchema( schemaName );
957        }
958
959        // Create the new LdapSyntax instance
960        LdapSyntax syntax = new LdapSyntax( oid );
961
962        // Common properties
963        setSchemaObjectProperties( syntax, entry, schema );
964
965        return syntax;
966    }
967
968
969    /**
970     * {@inheritDoc}
971     * @throws LdapInvalidAttributeValueException If the MatchingRule does not exist
972     * @throws LdapUnwillingToPerformException If the schema is not loaded
973     */
974    @Override
975    public MatchingRule getMatchingRule( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
976        String schemaName ) throws LdapUnwillingToPerformException, LdapInvalidAttributeValueException
977    {
978        checkEntry( entry, SchemaConstants.MATCHING_RULE );
979
980        // The MatchingRule OID
981        String oid = getOid( entry, SchemaConstants.MATCHING_RULE, schemaManager.isStrict() );
982
983        // Get the schema
984        if ( !schemaManager.isSchemaLoaded( schemaName ) )
985        {
986            // The schema is not loaded. We can't create the requested MatchingRule
987            String msg = I18n.err( I18n.ERR_16028_CANNOT_ADD_MR, entry.getDn().getName(), schemaName );
988            
989            if ( LOG.isWarnEnabled() )
990            {
991                LOG.warn( msg );
992            }
993            
994            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
995        }
996
997        Schema schema = getSchema( schemaName, targetRegistries );
998
999        if ( schema == null )
1000        {
1001            // The schema is disabled. We still have to update the backend
1002            if ( LOG.isInfoEnabled() )
1003            {
1004                LOG.info( I18n.err( I18n.ERR_16029_CANNOT_ADD_MR_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
1005            }
1006            
1007            schema = schemaManager.getLoadedSchema( schemaName );
1008        }
1009
1010        MatchingRule matchingRule = new MatchingRule( oid );
1011
1012        // The syntax field
1013        Attribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
1014
1015        if ( mSyntax != null )
1016        {
1017            matchingRule.setSyntaxOid( mSyntax.getString() );
1018        }
1019
1020        // The normalizer and comparator fields will be updated when we will
1021        // apply the registry
1022
1023        // Common properties
1024        setSchemaObjectProperties( matchingRule, entry, schema );
1025
1026        return matchingRule;
1027    }
1028
1029
1030    /**
1031     * Create a list of string from a multivalued attribute's values
1032     * 
1033     * @param attr The Attribute to read
1034     * @return The list of values as Strings
1035     */
1036    private List<String> getStrings( Attribute attr )
1037    {
1038        if ( attr == null )
1039        {
1040            return EMPTY_LIST;
1041        }
1042
1043        List<String> strings = new ArrayList<>( attr.size() );
1044
1045        for ( Value value : attr )
1046        {
1047            strings.add( value.getString() );
1048        }
1049
1050        return strings;
1051    }
1052
1053
1054    /**
1055     * {@inheritDoc}
1056     */
1057    @Override
1058    public ObjectClass getObjectClass( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
1059        String schemaName ) throws LdapException
1060    {
1061        checkEntry( entry, SchemaConstants.OBJECT_CLASS );
1062
1063        // The ObjectClass OID
1064        String oid = getOid( entry, SchemaConstants.OBJECT_CLASS, schemaManager.isStrict() );
1065
1066        // Get the schema
1067        if ( !schemaManager.isSchemaLoaded( schemaName ) )
1068        {
1069            // The schema is not loaded. We can't create the requested ObjectClass
1070            String msg = I18n.err( I18n.ERR_16030_CANNOT_ADD_OC, entry.getDn().getName(), schemaName );
1071            
1072            if ( LOG.isWarnEnabled() )
1073            {
1074                LOG.warn( msg );
1075            }
1076            
1077            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1078        }
1079
1080        Schema schema = getSchema( schemaName, targetRegistries );
1081
1082        if ( schema == null )
1083        {
1084            // The schema is disabled. We still have to update the backend
1085            if ( LOG.isInfoEnabled() )
1086            {
1087                LOG.info( I18n.err( I18n.ERR_16031_CANNOT_ADD_OC_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
1088            }
1089            
1090            schema = schemaManager.getLoadedSchema( schemaName );
1091        }
1092
1093        // Create the ObjectClass instance
1094        ObjectClass oc = new ObjectClass( oid );
1095
1096        // The Sup field
1097        Attribute mSuperiors = entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
1098
1099        if ( mSuperiors != null )
1100        {
1101            oc.setSuperiorOids( getStrings( mSuperiors ) );
1102        }
1103
1104        // The May field
1105        Attribute mMay = entry.get( MetaSchemaConstants.M_MAY_AT );
1106
1107        if ( mMay != null )
1108        {
1109            oc.setMayAttributeTypeOids( getStrings( mMay ) );
1110        }
1111
1112        // The Must field
1113        Attribute mMust = entry.get( MetaSchemaConstants.M_MUST_AT );
1114
1115        if ( mMust != null )
1116        {
1117            oc.setMustAttributeTypeOids( getStrings( mMust ) );
1118        }
1119
1120        // The objectClassType field
1121        Attribute mTypeObjectClass = entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT );
1122
1123        if ( mTypeObjectClass != null )
1124        {
1125            String type = mTypeObjectClass.getString();
1126            oc.setType( ObjectClassTypeEnum.getClassType( type ) );
1127        }
1128
1129        // Common properties
1130        setSchemaObjectProperties( oc, entry, schema );
1131
1132        return oc;
1133    }
1134
1135
1136    /**
1137     * {@inheritDoc}
1138     * @throws LdapInvalidAttributeValueException If the AttributeType does not exist
1139     * @throws LdapUnwillingToPerformException If the schema is not loaded
1140     */
1141    @Override
1142    public AttributeType getAttributeType( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
1143        String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
1144    {
1145        checkEntry( entry, SchemaConstants.ATTRIBUTE_TYPE );
1146
1147        // The AttributeType OID
1148        String oid = getOid( entry, SchemaConstants.ATTRIBUTE_TYPE, schemaManager.isStrict() );
1149
1150        // Get the schema
1151        if ( !schemaManager.isSchemaLoaded( schemaName ) )
1152        {
1153            // The schema is not loaded, this is an error
1154            String msg = I18n.err( I18n.ERR_16032_CANNOT_ADD_AT, entry.getDn().getName(), schemaName );
1155            
1156            if ( LOG.isWarnEnabled() )
1157            {
1158                LOG.warn( msg );
1159            }
1160            
1161            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1162        }
1163
1164        Schema schema = getSchema( schemaName, targetRegistries );
1165
1166        if ( schema == null )
1167        {
1168            // The schema is disabled. We still have to update the backend
1169            if ( LOG.isInfoEnabled() )
1170            {
1171                LOG.info( I18n.err( I18n.ERR_16033_CANNOT_ADD_AT_IN_REGISTRY, entry.getDn().getName(), schemaName ) );
1172            }
1173            
1174            schema = schemaManager.getLoadedSchema( schemaName );
1175        }
1176
1177        // Create the new AttributeType
1178        AttributeType attributeType = new AttributeType( oid );
1179        
1180        if ( schemaManager.isRelaxed() )
1181        {
1182            attributeType.setRelaxed( true );
1183        }
1184
1185        // Syntax
1186        Attribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
1187
1188        if ( ( mSyntax != null ) && ( mSyntax.get() != null ) )
1189        {
1190            attributeType.setSyntaxOid( mSyntax.getString() );
1191        }
1192
1193        // Syntax Length
1194        Attribute mSyntaxLength = entry.get( MetaSchemaConstants.M_LENGTH_AT );
1195
1196        if ( mSyntaxLength != null )
1197        {
1198            attributeType.setSyntaxLength( Integer.parseInt( mSyntaxLength.getString() ) );
1199        }
1200
1201        // Equality
1202        Attribute mEquality = entry.get( MetaSchemaConstants.M_EQUALITY_AT );
1203
1204        if ( mEquality != null )
1205        {
1206            attributeType.setEqualityOid( mEquality.getString() );
1207        }
1208
1209        // Ordering
1210        Attribute mOrdering = entry.get( MetaSchemaConstants.M_ORDERING_AT );
1211
1212        if ( mOrdering != null )
1213        {
1214            attributeType.setOrderingOid( mOrdering.getString() );
1215        }
1216
1217        // Substr
1218        Attribute mSubstr = entry.get( MetaSchemaConstants.M_SUBSTR_AT );
1219
1220        if ( mSubstr != null )
1221        {
1222            attributeType.setSubstringOid( mSubstr.getString() );
1223        }
1224
1225        Attribute mSupAttributeType = entry.get( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT );
1226
1227        // Sup
1228        if ( mSupAttributeType != null )
1229        {
1230            attributeType.setSuperiorOid( mSupAttributeType.getString() );
1231        }
1232
1233        // isCollective
1234        Attribute mCollective = entry.get( MetaSchemaConstants.M_COLLECTIVE_AT );
1235
1236        if ( mCollective != null )
1237        {
1238            String val = mCollective.getString();
1239            attributeType.setCollective( "TRUE".equalsIgnoreCase( val ) );
1240        }
1241
1242        // isSingleValued
1243        Attribute mSingleValued = entry.get( MetaSchemaConstants.M_SINGLE_VALUE_AT );
1244
1245        if ( mSingleValued != null )
1246        {
1247            String val = mSingleValued.getString();
1248            attributeType.setSingleValued( "TRUE".equalsIgnoreCase( val ) );
1249        }
1250
1251        // isReadOnly
1252        Attribute mNoUserModification = entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT );
1253
1254        if ( mNoUserModification != null )
1255        {
1256            String val = mNoUserModification.getString();
1257            attributeType.setUserModifiable( !"TRUE".equalsIgnoreCase( val ) );
1258        }
1259
1260        // Usage
1261        Attribute mUsage = entry.get( MetaSchemaConstants.M_USAGE_AT );
1262
1263        if ( mUsage != null )
1264        {
1265            attributeType.setUsage( UsageEnum.getUsage( mUsage.getString() ) );
1266        }
1267
1268        // Common properties
1269        setSchemaObjectProperties( attributeType, entry, schema );
1270
1271        return attributeType;
1272    }
1273
1274
1275    /**
1276     * Process the FQCN attribute
1277     * 
1278     * @param entry The entry to read
1279     * @param objectType The type of schema object
1280     * @return The schema object FQCN
1281     * @throws LdapInvalidAttributeValueException If the attribute does not contain a valid value
1282     */
1283    private String getFqcn( Entry entry, String objectType ) throws LdapInvalidAttributeValueException
1284    {
1285        // The FQCN
1286        Attribute mFqcn = entry.get( MetaSchemaConstants.M_FQCN_AT );
1287
1288        if ( mFqcn == null )
1289        {
1290            String msg = I18n.err( I18n.ERR_16034_ENTRY_WITHOUT_VALID_AT, objectType, MetaSchemaConstants.M_FQCN_AT );
1291            
1292            if ( LOG.isWarnEnabled() )
1293            {
1294                LOG.warn( msg );
1295            }
1296            
1297            throw new IllegalArgumentException( msg );
1298        }
1299
1300        return mFqcn.getString();
1301    }
1302
1303
1304    /**
1305     * Process the FQCN attribute
1306     * 
1307     * @param description The Schema Object description
1308     * @param objectType The SchemaObject type
1309     * @return The SchemaObject FQCN
1310     */
1311    private String getFqcn( LoadableSchemaObject description, String objectType )
1312    {
1313        // The FQCN
1314        String mFqcn = description.getFqcn();
1315
1316        if ( mFqcn == null )
1317        {
1318            String msg = I18n.err( I18n.ERR_16034_ENTRY_WITHOUT_VALID_AT, objectType, MetaSchemaConstants.M_FQCN_AT );
1319            
1320            if ( LOG.isWarnEnabled() )
1321            {
1322                LOG.warn( msg );
1323            }
1324            
1325            throw new IllegalArgumentException( msg );
1326        }
1327
1328        return mFqcn;
1329    }
1330
1331
1332    /**
1333     * Process the ByteCode attribute
1334     * 
1335     * @param description The SchemaObject description
1336     * @param objectType The SchemaObject type
1337     * @return The Attribute containing the byteCode
1338     */
1339    private Attribute getByteCode( LoadableSchemaObject description, String objectType )
1340    {
1341        String byteCodeString = description.getBytecode();
1342
1343        if ( byteCodeString == null )
1344        {
1345            String msg = I18n.err( I18n.ERR_16034_ENTRY_WITHOUT_VALID_AT, objectType, MetaSchemaConstants.M_BYTECODE_AT );
1346            
1347            if ( LOG.isWarnEnabled() )
1348            {
1349                LOG.warn( msg );
1350            }
1351            
1352            throw new IllegalArgumentException( msg );
1353        }
1354
1355        byte[] bytecode = Base64.decode( byteCodeString.toCharArray() );
1356        
1357        return new DefaultAttribute( MetaSchemaConstants.M_BYTECODE_AT, bytecode );
1358    }
1359
1360
1361    /**
1362     * Process the common attributes to all SchemaObjects :
1363     *  - obsolete
1364     *  - description
1365     *  - names
1366     *  - schemaName
1367     *  - specification (if any)
1368     *  - extensions
1369     *  - isReadOnly
1370     *  - isEnabled
1371     *  
1372     *  @param schemaObject The SchemaObject to set
1373     *  @param entry The entry containing the SchemaObject properties
1374     *  @param schema  the updated Schema 
1375     * @throws LdapInvalidAttributeValueException If some of the properties are invalid
1376     */
1377    private void setSchemaObjectProperties( SchemaObject schemaObject, Entry entry, Schema schema )
1378        throws LdapInvalidAttributeValueException
1379    {
1380        // The isObsolete field
1381        Attribute mObsolete = entry.get( MetaSchemaConstants.M_OBSOLETE_AT );
1382
1383        if ( mObsolete != null )
1384        {
1385            String val = mObsolete.getString();
1386            schemaObject.setObsolete( "TRUE".equalsIgnoreCase( val ) );
1387        }
1388
1389        // The description field
1390        Attribute mDescription = entry.get( MetaSchemaConstants.M_DESCRIPTION_AT );
1391
1392        if ( mDescription != null )
1393        {
1394            schemaObject.setDescription( mDescription.getString() );
1395        }
1396
1397        // The names field
1398        Attribute names = entry.get( MetaSchemaConstants.M_NAME_AT );
1399
1400        if ( names != null )
1401        {
1402            List<String> values = new ArrayList<>();
1403
1404            for ( Value name : names )
1405            {
1406                values.add( name.getString() );
1407            }
1408
1409            schemaObject.setNames( values );
1410        }
1411
1412        // The isEnabled field
1413        Attribute mDisabled = entry.get( MetaSchemaConstants.M_DISABLED_AT );
1414
1415        // If the SchemaObject has an explicit m-disabled attribute, then use it.
1416        // Otherwise, inherit it from the schema
1417        if ( mDisabled != null )
1418        {
1419            String val = mDisabled.getString();
1420            schemaObject.setEnabled( !"TRUE".equalsIgnoreCase( val ) );
1421        }
1422        else
1423        {
1424            schemaObject.setEnabled( schema.isEnabled() );
1425        }
1426
1427        // The specification field
1428        /*
1429         * TODO : create the M_SPECIFICATION_AT
1430        EntryAttribute mSpecification = entry.get( MetaSchemaConstants.M_SPECIFICATION_AT );
1431        
1432        if ( mSpecification != null )
1433        {
1434            so.setSpecification( mSpecification.getString() );
1435        }
1436        */
1437
1438        // The schemaName field
1439        schemaObject.setSchemaName( schema.getSchemaName() );
1440
1441        // The extensions fields
1442        // X-SCHEMA
1443        Attribute xSchema = entry.get( MetaSchemaConstants.X_SCHEMA_AT );
1444
1445        if ( xSchema != null )
1446        {
1447            String schemaName = xSchema.getString();
1448
1449            if ( !schema.getSchemaName().equalsIgnoreCase( schemaName ) )
1450            {
1451                if ( LOG.isWarnEnabled() )
1452                {
1453                    LOG.warn( I18n.msg( I18n.MSG_16011_SCHEMA_XSCHEMA_DIFF, schema.getSchemaName(), schemaName, entry ) );
1454                }
1455            }
1456
1457            schemaObject.addExtension( MetaSchemaConstants.X_SCHEMA_AT, schemaName );
1458        }
1459
1460        // X-NOT-HUMAN-READABLE
1461        Attribute xNotHumanReadable = entry.get( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT );
1462
1463        if ( xNotHumanReadable != null )
1464        {
1465            String value = xNotHumanReadable.getString();
1466
1467            schemaObject.addExtension( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT, value );
1468        }
1469
1470        // X-READ-ONLY
1471        Attribute xReadOnly = entry.get( MetaSchemaConstants.X_READ_ONLY_AT );
1472
1473        if ( xReadOnly != null )
1474        {
1475            String value = xReadOnly.getString();
1476
1477            schemaObject.addExtension( MetaSchemaConstants.X_READ_ONLY_AT, value );
1478        }
1479    }
1480
1481
1482    /**
1483     * Process the common attributes to all SchemaObjects :
1484     *  - obsolete
1485     *  - description
1486     *  - names
1487     *  - schemaName
1488     *  - specification (if any)
1489     *  - extensions
1490     *  - isEnabled
1491     *  
1492     *  @param schemaObject The SchemaObject to set
1493     *  @param description The SchemaObjetc description
1494     *  @param schema  the updated Schema 
1495     */
1496    private void setSchemaObjectProperties( SchemaObject schemaObject, SchemaObject description, Schema schema )
1497    {
1498        // The isObsolete field
1499        schemaObject.setObsolete( description.isObsolete() );
1500
1501        // The description field
1502        schemaObject.setDescription( description.getDescription() );
1503
1504        // The names field
1505        schemaObject.setNames( description.getNames() );
1506
1507        // The isEnabled field. Has the description does not hold a
1508        // Disable field, we will inherit from the schema enable field
1509        schemaObject.setEnabled( schema.isEnabled() );
1510
1511        // The specification field
1512        schemaObject.setSpecification( description.getSpecification() );
1513
1514        // The schemaName field
1515        schemaObject.setSchemaName( schema.getSchemaName() );
1516
1517        // The extensions field
1518        schemaObject.setExtensions( description.getExtensions() );
1519    }
1520}