View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.ldap.schema.loader;
21  
22  
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.security.AccessController;
27  import java.security.PrivilegedAction;
28  import java.util.ArrayList;
29  import java.util.Base64;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.Set;
33  
34  import org.apache.directory.api.asn1.util.Oid;
35  import org.apache.directory.api.i18n.I18n;
36  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
37  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
38  import org.apache.directory.api.ldap.model.entry.Attribute;
39  import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
40  import org.apache.directory.api.ldap.model.entry.Entry;
41  import org.apache.directory.api.ldap.model.entry.Value;
42  import org.apache.directory.api.ldap.model.exception.LdapException;
43  import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
44  import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
45  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
46  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
47  import org.apache.directory.api.ldap.model.schema.AttributeType;
48  import org.apache.directory.api.ldap.model.schema.LdapComparator;
49  import org.apache.directory.api.ldap.model.schema.LdapSyntax;
50  import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
51  import org.apache.directory.api.ldap.model.schema.MatchingRule;
52  import org.apache.directory.api.ldap.model.schema.ObjectClass;
53  import org.apache.directory.api.ldap.model.schema.Normalizer;
54  import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
55  import org.apache.directory.api.ldap.model.schema.SchemaManager;
56  import org.apache.directory.api.ldap.model.schema.SchemaObject;
57  import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
58  import org.apache.directory.api.ldap.model.schema.SyntaxChecker.SCBuilder;
59  import org.apache.directory.api.ldap.model.schema.UsageEnum;
60  import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
61  import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
62  import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
63  import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
64  import org.apache.directory.api.ldap.model.schema.registries.Registries;
65  import org.apache.directory.api.ldap.model.schema.registries.Schema;
66  import org.apache.directory.api.util.StringConstants;
67  import org.apache.directory.api.util.Strings;
68  import org.slf4j.Logger;
69  import org.slf4j.LoggerFactory;
70  
71  
72  /**
73   * Showing how it's done ...
74   *
75   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
76   */
77  public class SchemaEntityFactory implements EntityFactory
78  {
79      /** Slf4j logger */
80      private static final Logger LOG = LoggerFactory.getLogger( SchemaEntityFactory.class );
81  
82      /** The empty string list. */
83      private static final List<String> EMPTY_LIST = new ArrayList<>();
84  
85      /** The empty string array. */
86      private static final String[] EMPTY_ARRAY = new String[]
87          {};
88  
89      /** A special ClassLoader that loads a class from the bytecode attribute */
90      private final AttributeClassLoader classLoader;
91  
92  
93      /**
94       * Instantiates a new schema entity factory.
95       */
96      public SchemaEntityFactory()
97      {
98          this.classLoader = AccessController.doPrivileged( new PrivilegedAction<AttributeClassLoader>()
99          {
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.getEncoder().encodeToString( 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.getEncoder().encodeToString( 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.getEncoder().encodeToString( 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.getDecoder().decode( byteCodeString );
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 }