001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.schema.loader.ldif;
021
022
023 import java.lang.reflect.Constructor;
024 import java.lang.reflect.Method;
025 import java.util.ArrayList;
026 import java.util.HashSet;
027 import java.util.List;
028 import java.util.Set;
029
030 import org.apache.directory.shared.asn1.primitives.OID;
031 import org.apache.directory.shared.i18n.I18n;
032 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
033 import org.apache.directory.shared.ldap.constants.SchemaConstants;
034 import org.apache.directory.shared.ldap.entry.Entry;
035 import org.apache.directory.shared.ldap.entry.EntryAttribute;
036 import org.apache.directory.shared.ldap.entry.Value;
037 import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
038 import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
039 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
040 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
041 import org.apache.directory.shared.ldap.schema.AttributeType;
042 import org.apache.directory.shared.ldap.schema.EntityFactory;
043 import org.apache.directory.shared.ldap.schema.LdapComparator;
044 import org.apache.directory.shared.ldap.schema.LdapSyntax;
045 import org.apache.directory.shared.ldap.schema.LoadableSchemaObject;
046 import org.apache.directory.shared.ldap.schema.MatchingRule;
047 import org.apache.directory.shared.ldap.schema.Normalizer;
048 import org.apache.directory.shared.ldap.schema.ObjectClass;
049 import org.apache.directory.shared.ldap.schema.ObjectClassTypeEnum;
050 import org.apache.directory.shared.ldap.schema.SchemaManager;
051 import org.apache.directory.shared.ldap.schema.SchemaObject;
052 import org.apache.directory.shared.ldap.schema.SyntaxChecker;
053 import org.apache.directory.shared.ldap.schema.UsageEnum;
054 import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescription;
055 import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescription;
056 import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescription;
057 import org.apache.directory.shared.ldap.schema.registries.DefaultSchema;
058 import org.apache.directory.shared.ldap.schema.registries.Registries;
059 import org.apache.directory.shared.ldap.schema.registries.Schema;
060 import org.apache.directory.shared.ldap.util.Base64;
061 import org.apache.directory.shared.ldap.util.StringTools;
062 import org.slf4j.Logger;
063 import org.slf4j.LoggerFactory;
064
065
066 /**
067 * Showing how it's done ...
068 *
069 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
070 * @version $Rev$
071 */
072 public class SchemaEntityFactory implements EntityFactory
073 {
074 /** Slf4j logger */
075 private final static Logger LOG = LoggerFactory.getLogger( SchemaEntityFactory.class );
076
077 /** for fast debug checks */
078 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
079
080 /** Used for looking up the setRegistries(Registries) method */
081 private final static Class<?>[] parameterTypes = new Class[]
082 { Registries.class };
083
084 private static final List<String> EMPTY_LIST = new ArrayList<String>();
085 private static final String[] EMPTY_ARRAY = new String[]
086 {};
087
088 /** A special ClassLoader that loads a class from the bytecode attribute */
089 private final AttributeClassLoader classLoader;
090
091
092 public SchemaEntityFactory() throws Exception
093 {
094 this.classLoader = new AttributeClassLoader();
095 }
096
097
098 /**
099 * Get an OID from an entry. Handles the bad cases (null OID,
100 * not a valid OID, ...)
101 */
102 private String getOid( Entry entry, String objectType ) throws LdapInvalidAttributeValueException
103 {
104 // The OID
105 EntryAttribute mOid = entry.get( MetaSchemaConstants.M_OID_AT );
106
107 if ( mOid == null )
108 {
109 String msg = I18n.err( I18n.ERR_10005, objectType, MetaSchemaConstants.M_OID_AT );
110 LOG.warn( msg );
111 throw new NullPointerException( msg );
112 }
113
114 String oid = mOid.getString();
115
116 if ( !OID.isOID( oid ) )
117 {
118 String msg = I18n.err( I18n.ERR_10006, oid );
119 LOG.warn( msg );
120 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
121 }
122
123 return oid;
124 }
125
126
127 /**
128 * Get an OID from an entry. Handles the bad cases (null OID,
129 * not a valid OID, ...)
130 */
131 private String getOid( SchemaObject description, String objectType ) throws LdapInvalidAttributeValueException
132 {
133 // The OID
134 String oid = description.getOid();
135
136 if ( oid == null )
137 {
138 String msg = I18n.err( I18n.ERR_10005, objectType, MetaSchemaConstants.M_OID_AT );
139 LOG.warn( msg );
140 throw new NullPointerException( msg );
141 }
142
143 if ( !OID.isOID( oid ) )
144 {
145 String msg = I18n.err( I18n.ERR_10006, oid );
146 LOG.warn( msg );
147 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
148 }
149
150 return oid;
151 }
152
153
154 /**
155 * Check that the Entry is not null
156 */
157 private void checkEntry( Entry entry, String schemaEntity )
158 {
159 if ( entry == null )
160 {
161 String msg = I18n.err( I18n.ERR_10007, schemaEntity );
162 LOG.warn( msg );
163 throw new NullPointerException( msg );
164 }
165 }
166
167
168 /**
169 * Check that the Description is not null
170 */
171 private void checkDescription( SchemaObject description, String schemaEntity )
172 {
173 if ( description == null )
174 {
175 String msg = I18n.err( I18n.ERR_10008, schemaEntity );
176 LOG.warn( msg );
177 throw new NullPointerException( msg );
178 }
179 }
180
181
182 /**
183 * Get the schema from its name. Return the Other reference if there
184 * is no schema name. Throws a NPE if the schema is not loaded.
185 */
186 private Schema getSchema( String schemaName, Registries registries )
187 {
188 if ( StringTools.isEmpty( schemaName ) )
189 {
190 schemaName = MetaSchemaConstants.SCHEMA_OTHER;
191 }
192
193 Schema schema = registries.getLoadedSchema( schemaName );
194
195 if ( schema == null )
196 {
197 String msg = I18n.err( I18n.ERR_10009, schemaName );
198 LOG.error( msg );
199 }
200
201 return schema;
202 }
203
204
205 /**
206 * {@inheritDoc}
207 */
208 public Schema getSchema( Entry entry ) throws Exception
209 {
210 String name;
211 String owner;
212 String[] dependencies = EMPTY_ARRAY;
213 boolean isDisabled = false;
214
215 if ( entry == null )
216 {
217 throw new NullPointerException( I18n.err( I18n.ERR_10010 ) );
218 }
219
220 if ( entry.get( SchemaConstants.CN_AT ) == null )
221 {
222 throw new NullPointerException( I18n.err( I18n.ERR_10011 ) );
223 }
224
225 name = entry.get( SchemaConstants.CN_AT ).getString();
226
227 if ( entry.get( SchemaConstants.CREATORS_NAME_AT ) == null )
228 {
229 throw new NullPointerException( I18n.err( I18n.ERR_10012, SchemaConstants.CREATORS_NAME_AT ) );
230 }
231
232 owner = entry.get( SchemaConstants.CREATORS_NAME_AT ).getString();
233
234 if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
235 {
236 String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
237 value = value.toUpperCase();
238 isDisabled = value.equals( "TRUE" );
239 }
240
241 if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
242 {
243 Set<String> depsSet = new HashSet<String>();
244 EntryAttribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
245
246 for ( Value<?> value : depsAttr )
247 {
248 depsSet.add( value.getString() );
249 }
250
251 dependencies = depsSet.toArray( EMPTY_ARRAY );
252 }
253
254 return new DefaultSchema( name, owner, dependencies, isDisabled );
255 }
256
257
258 /**
259 * Class load a syntaxChecker instance
260 */
261 private SyntaxChecker classLoadSyntaxChecker( SchemaManager schemaManager, String oid, String className,
262 EntryAttribute byteCode, Registries targetRegistries ) throws Exception
263 {
264 // Try to class load the syntaxChecker
265 Class<?> clazz = null;
266 SyntaxChecker syntaxChecker = null;
267 String byteCodeStr = StringTools.EMPTY;
268
269 if ( byteCode == null )
270 {
271 clazz = Class.forName( className );
272 }
273 else
274 {
275 classLoader.setAttribute( byteCode );
276 clazz = classLoader.loadClass( className );
277 byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
278 }
279
280 // Create the syntaxChecker instance
281 syntaxChecker = ( SyntaxChecker ) clazz.newInstance();
282
283 // Update the common fields
284 syntaxChecker.setBytecode( byteCodeStr );
285 syntaxChecker.setFqcn( className );
286
287 // Inject the new OID, as the loaded syntaxChecker might have its own
288 syntaxChecker.setOid( oid );
289
290 return syntaxChecker;
291 }
292
293
294 /**
295 * {@inheritDoc}
296 */
297 public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
298 String schemaName ) throws Exception
299 {
300 checkEntry( entry, SchemaConstants.SYNTAX_CHECKER );
301
302 // The SyntaxChecker OID
303 String oid = getOid( entry, SchemaConstants.SYNTAX_CHECKER );
304
305 // Get the schema
306 if ( !schemaManager.isSchemaLoaded( schemaName ) )
307 {
308 // The schema is not loaded. We can't create the requested Normalizer
309 String msg = I18n.err( I18n.ERR_10013, entry.getDn().getName(), schemaName );
310 LOG.warn( msg );
311 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
312 }
313
314 Schema schema = getSchema( schemaName, targetRegistries );
315
316 if ( schema == null )
317 {
318 // The schema is disabled. We still have to update the backend
319 String msg = I18n.err( I18n.ERR_10014, entry.getDn().getName(), schemaName );
320 LOG.info( msg );
321 schema = schemaManager.getLoadedSchema( schemaName );
322 }
323
324 // The FQCN
325 String className = getFqcn( entry, SchemaConstants.SYNTAX_CHECKER );
326
327 // The ByteCode
328 EntryAttribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
329
330 // Class load the syntaxChecker
331 SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, className, byteCode, targetRegistries );
332
333 // Update the common fields
334 setSchemaObjectProperties( syntaxChecker, entry, schema );
335
336 // return the resulting syntaxChecker
337 return syntaxChecker;
338 }
339
340
341 /**
342 * {@inheritDoc}
343 */
344 public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager,
345 SyntaxCheckerDescription syntaxCheckerDescription, Registries targetRegistries, String schemaName )
346 throws Exception
347 {
348 checkDescription( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
349
350 // The Comparator OID
351 String oid = getOid( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
352
353 // Get the schema
354 Schema schema = getSchema( schemaName, targetRegistries );
355
356 if ( schema == null )
357 {
358 // The schema is not loaded. We can't create the requested SyntaxChecker
359 String msg = I18n.err( I18n.ERR_10013, syntaxCheckerDescription.getName(), schemaName );
360 LOG.warn( msg );
361 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
362 }
363
364 // The FQCN
365 String fqcn = getFqcn( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
366
367 // get the byteCode
368 EntryAttribute byteCode = getByteCode( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
369
370 // Class load the SyntaxChecker
371 SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, fqcn, byteCode, targetRegistries );
372
373 // Update the common fields
374 setSchemaObjectProperties( syntaxChecker, syntaxCheckerDescription, schema );
375
376 return syntaxChecker;
377 }
378
379
380 /**
381 * Class load a comparator instances
382 */
383 private LdapComparator<?> classLoadComparator( SchemaManager schemaManager, String oid, String className,
384 EntryAttribute byteCode, Registries targetRegistries ) throws Exception
385 {
386 // Try to class load the comparator
387 LdapComparator<?> comparator = null;
388 Class<?> clazz = null;
389 String byteCodeStr = StringTools.EMPTY;
390
391 if ( byteCode == null )
392 {
393 clazz = Class.forName( className );
394 }
395 else
396 {
397 classLoader.setAttribute( byteCode );
398 clazz = classLoader.loadClass( className );
399 byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
400 }
401
402 // Create the comparator instance. Either we have a no argument constructor,
403 // or we have one which takes an OID. Lets try the one with an OID argument first
404 try
405 {
406 Constructor<?> constructor = clazz.getConstructor( new Class[]
407 { String.class } );
408 comparator = ( LdapComparator<?> ) constructor.newInstance( new Object[]
409 { oid } );
410 }
411 catch ( NoSuchMethodException nsme )
412 {
413 // Ok, let's try with the constructor without argument.
414 // In this case, we will have to check that the OID is the same than
415 // the one we got in the Comparator entry
416 Constructor<?> constructor = clazz.getConstructor();
417 comparator = ( LdapComparator<?> ) clazz.newInstance();
418
419 if ( !comparator.getOid().equals( oid ) )
420 {
421 String msg = I18n.err( I18n.ERR_10015, oid, comparator.getOid() );
422 throw new LdapInvalidAttributeValueException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
423 }
424 }
425
426 // Update the loadable fields
427 comparator.setBytecode( byteCodeStr );
428 comparator.setFqcn( className );
429
430 // Inject the SchemaManager for the comparator who needs it
431 comparator.setSchemaManager( schemaManager );
432
433 return comparator;
434 }
435
436
437 /**
438 * {@inheritDoc}
439 */
440 public LdapComparator<?> getLdapComparator( SchemaManager schemaManager,
441 LdapComparatorDescription comparatorDescription, Registries targetRegistries, String schemaName )
442 throws Exception
443 {
444 checkDescription( comparatorDescription, SchemaConstants.COMPARATOR );
445
446 // The Comparator OID
447 String oid = getOid( comparatorDescription, SchemaConstants.COMPARATOR );
448
449 // Get the schema
450 Schema schema = getSchema( schemaName, targetRegistries );
451
452 if ( schema == null )
453 {
454 // The schema is not loaded. We can't create the requested Comparator
455 String msg = I18n.err( I18n.ERR_10016, comparatorDescription.getName(), schemaName );
456 LOG.warn( msg );
457 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
458 }
459
460 // The FQCN
461 String fqcn = getFqcn( comparatorDescription, SchemaConstants.COMPARATOR );
462
463 // get the byteCode
464 EntryAttribute byteCode = getByteCode( comparatorDescription, SchemaConstants.COMPARATOR );
465
466 // Class load the comparator
467 LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode, targetRegistries );
468
469 // Update the common fields
470 setSchemaObjectProperties( comparator, comparatorDescription, schema );
471
472 return comparator;
473 }
474
475
476 /**
477 * {@inheritDoc}
478 */
479 public LdapComparator<?> getLdapComparator( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
480 String schemaName ) throws Exception
481 {
482 checkEntry( entry, SchemaConstants.COMPARATOR );
483
484 // The Comparator OID
485 String oid = getOid( entry, SchemaConstants.COMPARATOR );
486
487 // Get the schema
488 if ( !schemaManager.isSchemaLoaded( schemaName ) )
489 {
490 // The schema is not loaded. We can't create the requested Comparator
491 String msg = I18n.err( I18n.ERR_10016, entry.getDn().getName(), schemaName );
492 LOG.warn( msg );
493 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
494 }
495
496 Schema schema = getSchema( schemaName, targetRegistries );
497
498 if ( schema == null )
499 {
500 // The schema is disabled. We still have to update the backend
501 String msg = I18n.err( I18n.ERR_10017, entry.getDn().getName(), schemaName );
502 LOG.info( msg );
503 schema = schemaManager.getLoadedSchema( schemaName );
504 }
505
506 // The FQCN
507 String fqcn = getFqcn( entry, SchemaConstants.COMPARATOR );
508
509 // The ByteCode
510 EntryAttribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
511
512 // Class load the comparator
513 LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode, targetRegistries );
514
515 // Update the common fields
516 setSchemaObjectProperties( comparator, entry, schema );
517
518 // return the resulting comparator
519 return comparator;
520 }
521
522
523 /**
524 * Class load a normalizer instances
525 */
526 private Normalizer classLoadNormalizer( SchemaManager schemaManager, String oid, String className,
527 EntryAttribute byteCode, Registries targetRegistries ) throws Exception
528 {
529 // Try to class load the normalizer
530 Class<?> clazz = null;
531 Normalizer normalizer = null;
532 String byteCodeStr = StringTools.EMPTY;
533
534 if ( byteCode == null )
535 {
536 clazz = Class.forName( className );
537 }
538 else
539 {
540 classLoader.setAttribute( byteCode );
541 clazz = classLoader.loadClass( className );
542 byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
543 }
544
545 // Create the normalizer instance
546 normalizer = ( Normalizer ) clazz.newInstance();
547
548 // Update the common fields
549 normalizer.setBytecode( byteCodeStr );
550 normalizer.setFqcn( className );
551
552 // Inject the new OID, as the loaded normalizer might have its own
553 normalizer.setOid( oid );
554
555 // Inject the SchemaManager for the normalizer who needs it
556 normalizer.setSchemaManager( schemaManager );
557
558 return normalizer;
559 }
560
561
562 /**
563 * {@inheritDoc}
564 */
565 public Normalizer getNormalizer( SchemaManager schemaManager, NormalizerDescription normalizerDescription,
566 Registries targetRegistries, String schemaName ) throws Exception
567 {
568 checkDescription( normalizerDescription, SchemaConstants.NORMALIZER );
569
570 // The Comparator OID
571 String oid = getOid( normalizerDescription, SchemaConstants.NORMALIZER );
572
573 // Get the schema
574 Schema schema = getSchema( schemaName, targetRegistries );
575
576 if ( schema == null )
577 {
578 // The schema is not loaded. We can't create the requested Normalizer
579 String msg = I18n.err( I18n.ERR_10018, normalizerDescription.getName(), schemaName );
580 LOG.warn( msg );
581 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
582 }
583
584 // The FQCN
585 String fqcn = getFqcn( normalizerDescription, SchemaConstants.NORMALIZER );
586
587 // get the byteCode
588 EntryAttribute byteCode = getByteCode( normalizerDescription, SchemaConstants.NORMALIZER );
589
590 // Class load the normalizer
591 Normalizer normalizer = classLoadNormalizer( schemaManager, oid, fqcn, byteCode, targetRegistries );
592
593 // Update the common fields
594 setSchemaObjectProperties( normalizer, normalizerDescription, schema );
595
596 return normalizer;
597 }
598
599
600 /**
601 * {@inheritDoc}
602 */
603 public Normalizer getNormalizer( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
604 String schemaName ) throws Exception
605 {
606 checkEntry( entry, SchemaConstants.NORMALIZER );
607
608 // The Normalizer OID
609 String oid = getOid( entry, SchemaConstants.NORMALIZER );
610
611 // Get the schema
612 if ( !schemaManager.isSchemaLoaded( schemaName ) )
613 {
614 // The schema is not loaded. We can't create the requested Normalizer
615 String msg = I18n.err( I18n.ERR_10018, entry.getDn().getName(), schemaName );
616 LOG.warn( msg );
617 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
618 }
619
620 Schema schema = getSchema( schemaName, targetRegistries );
621
622 if ( schema == null )
623 {
624 // The schema is disabled. We still have to update the backend
625 String msg = I18n.err( I18n.ERR_10019, entry.getDn().getName(), schemaName );
626 LOG.info( msg );
627 schema = schemaManager.getLoadedSchema( schemaName );
628 }
629
630 // The FQCN
631 String className = getFqcn( entry, SchemaConstants.NORMALIZER );
632
633 // The ByteCode
634 EntryAttribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
635
636 // Class load the Normalizer
637 Normalizer normalizer = classLoadNormalizer( schemaManager, oid, className, byteCode, targetRegistries );
638
639 // Update the common fields
640 setSchemaObjectProperties( normalizer, entry, schema );
641
642 // return the resulting Normalizer
643 return normalizer;
644 }
645
646
647 /**
648 * Uses reflection to see if a setRegistries( Registries ) method exists on the
649 * object's class. If so then the registries are dependency injected into the
650 * new schema object.
651 *
652 * @param obj a schema object to have a Registries dependency injected.
653 */
654 private void injectRegistries( Object obj, Registries targetRegistries ) throws Exception
655 {
656 Method method = null;
657
658 try
659 {
660 method = obj.getClass().getMethod( "setRegistries", parameterTypes );
661 }
662 catch ( NoSuchMethodException e )
663 {
664 if ( IS_DEBUG )
665 {
666 LOG.debug( obj.getClass() + " has no setRegistries() method." );
667 }
668
669 return;
670 }
671
672 if ( method == null )
673 {
674 return;
675 }
676
677 Object[] args = new Object[]
678 { targetRegistries };
679 method.invoke( obj, args );
680 }
681
682
683 /**
684 * {@inheritDoc}
685 * @throws LdapInvalidAttributeValueException
686 * @throws LdapUnwillingToPerformException
687 */
688 public LdapSyntax getSyntax( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
689 String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
690 {
691 checkEntry( entry, SchemaConstants.SYNTAX );
692
693 // The Syntax OID
694 String oid = getOid( entry, SchemaConstants.SYNTAX );
695
696 // Get the schema
697 if ( !schemaManager.isSchemaLoaded( schemaName ) )
698 {
699 // The schema is not loaded. We can't create the requested Syntax
700 String msg = I18n.err( I18n.ERR_10020, entry.getDn().getName(), schemaName );
701 LOG.warn( msg );
702 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
703 }
704
705 Schema schema = getSchema( schemaName, targetRegistries );
706
707 if ( schema == null )
708 {
709 // The schema is disabled. We still have to update the backend
710 String msg = I18n.err( I18n.ERR_10021, entry.getDn().getName(), schemaName );
711 LOG.info( msg );
712 schema = schemaManager.getLoadedSchema( schemaName );
713 }
714
715 // Create the new LdapSyntax instance
716 LdapSyntax syntax = new LdapSyntax( oid );
717
718 // The isHumanReadable field
719 EntryAttribute mHumanReadable = entry.get( MetaSchemaConstants.X_HUMAN_READABLE_AT );
720
721 if ( mHumanReadable != null )
722 {
723 String val = mHumanReadable.getString();
724 syntax.setHumanReadable( val.toUpperCase().equals( "TRUE" ) );
725 }
726
727 // Common properties
728 setSchemaObjectProperties( syntax, entry, schema );
729
730 return syntax;
731 }
732
733
734 /**
735 * {@inheritDoc}
736 * @throws LdapUnwillingToPerformException
737 * @throws LdapInvalidAttributeValueException
738 */
739 public MatchingRule getMatchingRule( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
740 String schemaName ) throws LdapUnwillingToPerformException, LdapInvalidAttributeValueException
741 {
742 checkEntry( entry, SchemaConstants.MATCHING_RULE );
743
744 // The MatchingRule OID
745 String oid = getOid( entry, SchemaConstants.MATCHING_RULE );
746
747 // Get the schema
748 if ( !schemaManager.isSchemaLoaded( schemaName ) )
749 {
750 // The schema is not loaded. We can't create the requested MatchingRule
751 String msg = I18n.err( I18n.ERR_10022, entry.getDn().getName(), schemaName );
752 LOG.warn( msg );
753 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
754 }
755
756 Schema schema = getSchema( schemaName, targetRegistries );
757
758 if ( schema == null )
759 {
760 // The schema is disabled. We still have to update the backend
761 String msg = I18n.err( I18n.ERR_10023, entry.getDn().getName(), schemaName );
762 LOG.info( msg );
763 schema = schemaManager.getLoadedSchema( schemaName );
764 }
765
766 MatchingRule matchingRule = new MatchingRule( oid );
767
768 // The syntax field
769 EntryAttribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
770
771 if ( mSyntax != null )
772 {
773 matchingRule.setSyntaxOid( mSyntax.getString() );
774 }
775
776 // The normalizer and comparator fields will be updated when we will
777 // apply the registry
778
779 // Common properties
780 setSchemaObjectProperties( matchingRule, entry, schema );
781
782 return matchingRule;
783 }
784
785
786 /**
787 * Create a list of string from a multivalued attribute's values
788 */
789 private List<String> getStrings( EntryAttribute attr )
790 {
791 if ( attr == null )
792 {
793 return EMPTY_LIST;
794 }
795
796 List<String> strings = new ArrayList<String>( attr.size() );
797
798 for ( Value<?> value : attr )
799 {
800 strings.add( value.getString() );
801 }
802
803 return strings;
804 }
805
806
807 /**
808 * {@inheritDoc}
809 */
810 public ObjectClass getObjectClass( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
811 String schemaName ) throws Exception
812 {
813 checkEntry( entry, SchemaConstants.OBJECT_CLASS );
814
815 // The ObjectClass OID
816 String oid = getOid( entry, SchemaConstants.OBJECT_CLASS );
817
818 // Get the schema
819 if ( !schemaManager.isSchemaLoaded( schemaName ) )
820 {
821 // The schema is not loaded. We can't create the requested ObjectClass
822 String msg = I18n.err( I18n.ERR_10024, entry.getDn().getName(), schemaName );
823 LOG.warn( msg );
824 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
825 }
826
827 Schema schema = getSchema( schemaName, targetRegistries );
828
829 if ( schema == null )
830 {
831 // The schema is disabled. We still have to update the backend
832 String msg = I18n.err( I18n.ERR_10025, entry.getDn().getName(), schemaName );
833 LOG.info( msg );
834 schema = schemaManager.getLoadedSchema( schemaName );
835 }
836
837 // Create the ObjectClass instance
838 ObjectClass oc = new ObjectClass( oid );
839
840 // The Sup field
841 EntryAttribute mSuperiors = entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
842
843 if ( mSuperiors != null )
844 {
845 oc.setSuperiorOids( getStrings( mSuperiors ) );
846 }
847
848 // The May field
849 EntryAttribute mMay = entry.get( MetaSchemaConstants.M_MAY_AT );
850
851 if ( mMay != null )
852 {
853 oc.setMayAttributeTypeOids( getStrings( mMay ) );
854 }
855
856 // The Must field
857 EntryAttribute mMust = entry.get( MetaSchemaConstants.M_MUST_AT );
858
859 if ( mMust != null )
860 {
861 oc.setMustAttributeTypeOids( getStrings( mMust ) );
862 }
863
864 // The objectClassType field
865 EntryAttribute mTypeObjectClass = entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT );
866
867 if ( mTypeObjectClass != null )
868 {
869 String type = mTypeObjectClass.getString();
870 oc.setType( ObjectClassTypeEnum.getClassType( type ) );
871 }
872
873 // Common properties
874 setSchemaObjectProperties( oc, entry, schema );
875
876 return oc;
877 }
878
879
880 /**
881 * {@inheritDoc}
882 * @throws LdapInvalidAttributeValueException
883 * @throws LdapUnwillingToPerformException
884 */
885 public AttributeType getAttributeType( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
886 String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
887 {
888 checkEntry( entry, SchemaConstants.ATTRIBUTE_TYPE );
889
890 // The AttributeType OID
891 String oid = getOid( entry, SchemaConstants.ATTRIBUTE_TYPE );
892
893 // Get the schema
894 if ( !schemaManager.isSchemaLoaded( schemaName ) )
895 {
896 // The schema is not loaded, this is an error
897 String msg = I18n.err( I18n.ERR_10026, entry.getDn().getName(), schemaName );
898 LOG.warn( msg );
899 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
900 }
901
902 Schema schema = getSchema( schemaName, targetRegistries );
903
904 if ( schema == null )
905 {
906 // The schema is disabled. We still have to update the backend
907 String msg = I18n.err( I18n.ERR_10027, entry.getDn().getName(), schemaName );
908 LOG.info( msg );
909 schema = schemaManager.getLoadedSchema( schemaName );
910 }
911
912 // Create the new AttributeType
913 AttributeType attributeType = new AttributeType( oid );
914
915 // Syntax
916 EntryAttribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
917
918 if ( ( mSyntax != null ) && ( mSyntax.get() != null ) )
919 {
920 attributeType.setSyntaxOid( mSyntax.getString() );
921 }
922
923 // Syntax Length
924 EntryAttribute mSyntaxLength = entry.get( MetaSchemaConstants.M_LENGTH_AT );
925
926 if ( mSyntaxLength != null )
927 {
928 attributeType.setSyntaxLength( Integer.parseInt( mSyntaxLength.getString() ) );
929 }
930
931 // Equality
932 EntryAttribute mEquality = entry.get( MetaSchemaConstants.M_EQUALITY_AT );
933
934 if ( mEquality != null )
935 {
936 attributeType.setEqualityOid( mEquality.getString() );
937 }
938
939 // Ordering
940 EntryAttribute mOrdering = entry.get( MetaSchemaConstants.M_ORDERING_AT );
941
942 if ( mOrdering != null )
943 {
944 attributeType.setOrderingOid( mOrdering.getString() );
945 }
946
947 // Substr
948 EntryAttribute mSubstr = entry.get( MetaSchemaConstants.M_SUBSTR_AT );
949
950 if ( mSubstr != null )
951 {
952 attributeType.setSubstringOid( mSubstr.getString() );
953 }
954
955 EntryAttribute mSupAttributeType = entry.get( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT );
956
957 // Sup
958 if ( mSupAttributeType != null )
959 {
960 attributeType.setSuperiorOid( mSupAttributeType.getString() );
961 }
962
963 // isCollective
964 EntryAttribute mCollective = entry.get( MetaSchemaConstants.M_COLLECTIVE_AT );
965
966 if ( mCollective != null )
967 {
968 String val = mCollective.getString();
969 attributeType.setCollective( val.equalsIgnoreCase( "TRUE" ) );
970 }
971
972 // isSingleValued
973 EntryAttribute mSingleValued = entry.get( MetaSchemaConstants.M_SINGLE_VALUE_AT );
974
975 if ( mSingleValued != null )
976 {
977 String val = mSingleValued.getString();
978 attributeType.setSingleValued( val.equalsIgnoreCase( "TRUE" ) );
979 }
980
981 // isReadOnly
982 EntryAttribute mNoUserModification = entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT );
983
984 if ( mNoUserModification != null )
985 {
986 String val = mNoUserModification.getString();
987 attributeType.setUserModifiable( !val.equalsIgnoreCase( "TRUE" ) );
988 }
989
990 // Usage
991 EntryAttribute mUsage = entry.get( MetaSchemaConstants.M_USAGE_AT );
992
993 if ( mUsage != null )
994 {
995 attributeType.setUsage( UsageEnum.getUsage( mUsage.getString() ) );
996 }
997
998 // Common properties
999 setSchemaObjectProperties( attributeType, entry, schema );
1000
1001 return attributeType;
1002 }
1003
1004
1005 /**
1006 * Process the FQCN attribute
1007 * @throws LdapInvalidAttributeValueException
1008 */
1009 private String getFqcn( Entry entry, String objectType ) throws LdapInvalidAttributeValueException
1010 {
1011 // The FQCN
1012 EntryAttribute mFqcn = entry.get( MetaSchemaConstants.M_FQCN_AT );
1013
1014 if ( mFqcn == null )
1015 {
1016 String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_FQCN_AT );
1017 LOG.warn( msg );
1018 throw new NullPointerException( msg );
1019 }
1020
1021 return mFqcn.getString();
1022 }
1023
1024
1025 /**
1026 * Process the FQCN attribute
1027 */
1028 private String getFqcn( LoadableSchemaObject description, String objectType )
1029 {
1030 // The FQCN
1031 String mFqcn = description.getFqcn();
1032
1033 if ( mFqcn == null )
1034 {
1035 String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_FQCN_AT );
1036 LOG.warn( msg );
1037 throw new NullPointerException( msg );
1038 }
1039
1040 return mFqcn;
1041 }
1042
1043
1044 /**
1045 * Process the ByteCode attribute
1046 */
1047 private EntryAttribute getByteCode( Entry entry, String objectType )
1048 {
1049 EntryAttribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
1050
1051 if ( byteCode == null )
1052 {
1053 String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_BYTECODE_AT );
1054 LOG.warn( msg );
1055 throw new NullPointerException( msg );
1056 }
1057
1058 return byteCode;
1059 }
1060
1061
1062 /**
1063 * Process the ByteCode attribute
1064 */
1065 private EntryAttribute getByteCode( LoadableSchemaObject description, String objectType )
1066 {
1067 String byteCodeString = description.getBytecode();
1068
1069 if ( byteCodeString == null )
1070 {
1071 String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_BYTECODE_AT );
1072 LOG.warn( msg );
1073 throw new NullPointerException( msg );
1074 }
1075
1076 byte[] bytecode = Base64.decode( byteCodeString.toCharArray() );
1077 EntryAttribute attr = new DefaultClientAttribute( MetaSchemaConstants.M_BYTECODE_AT, bytecode );
1078
1079 return attr;
1080 }
1081
1082
1083 /**
1084 * Process the common attributes to all SchemaObjects :
1085 * - obsolete
1086 * - description
1087 * - names
1088 * - schemaName
1089 * - specification (if any)
1090 * - extensions
1091 * - isReadOnly
1092 * - isEnabled
1093 * @throws LdapInvalidAttributeValueException
1094 */
1095 private void setSchemaObjectProperties( SchemaObject schemaObject, Entry entry, Schema schema ) throws LdapInvalidAttributeValueException
1096 {
1097 // The isObsolete field
1098 EntryAttribute mObsolete = entry.get( MetaSchemaConstants.M_OBSOLETE_AT );
1099
1100 if ( mObsolete != null )
1101 {
1102 String val = mObsolete.getString();
1103 schemaObject.setObsolete( val.equalsIgnoreCase( "TRUE" ) );
1104 }
1105
1106 // The description field
1107 EntryAttribute mDescription = entry.get( MetaSchemaConstants.M_DESCRIPTION_AT );
1108
1109 if ( mDescription != null )
1110 {
1111 schemaObject.setDescription( mDescription.getString() );
1112 }
1113
1114 // The names field
1115 EntryAttribute names = entry.get( MetaSchemaConstants.M_NAME_AT );
1116
1117 if ( names != null )
1118 {
1119 List<String> values = new ArrayList<String>();
1120
1121 for ( Value<?> name : names )
1122 {
1123 values.add( name.getString() );
1124 }
1125
1126 schemaObject.setNames( values );
1127 }
1128
1129 // The isEnabled field
1130 EntryAttribute mDisabled = entry.get( MetaSchemaConstants.M_DISABLED_AT );
1131
1132 // If the SchemaObject has an explicit m-disabled attribute, then use it.
1133 // Otherwise, inherit it from the schema
1134 if ( mDisabled != null )
1135 {
1136 String val = mDisabled.getString();
1137 schemaObject.setEnabled( !val.equalsIgnoreCase( "TRUE" ) );
1138 }
1139 else
1140 {
1141 schemaObject.setEnabled( schema != null && schema.isEnabled() );
1142 }
1143
1144 // The isReadOnly field
1145 EntryAttribute mIsReadOnly = entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT );
1146
1147 if ( mIsReadOnly != null )
1148 {
1149 String val = mIsReadOnly.getString();
1150 schemaObject.setReadOnly( val.equalsIgnoreCase( "TRUE" ) );
1151 }
1152
1153 // The specification field
1154 /*
1155 * TODO : create the M_SPECIFICATION_AT
1156 EntryAttribute mSpecification = entry.get( MetaSchemaConstants.M_SPECIFICATION_AT );
1157
1158 if ( mSpecification != null )
1159 {
1160 so.setSpecification( mSpecification.getString() );
1161 }
1162 */
1163
1164 // The schemaName field
1165 schemaObject.setSchemaName( schema.getSchemaName() );
1166
1167 // The extensions field
1168 /*
1169 * TODO create the M_EXTENSION_AT AT
1170 EntryAttribute extensions = entry.get( MetaSchemaConstants.M_EXTENSION_AT );
1171
1172 if ( extensions != null )
1173 {
1174 List<String> extensions = new ArrayList<String>();
1175
1176 for ( Value<?> extension:extensions )
1177 {
1178 values.add( extension() );
1179 }
1180
1181 so.setExtensions( values );
1182 }
1183 */
1184 }
1185
1186
1187 /**
1188 * Process the common attributes to all SchemaObjects :
1189 * - obsolete
1190 * - description
1191 * - names
1192 * - schemaName
1193 * - specification (if any)
1194 * - extensions
1195 * - isReadOnly
1196 * - isEnabled
1197 */
1198 private void setSchemaObjectProperties( SchemaObject schemaObject, SchemaObject description, Schema schema )
1199 {
1200 // The isObsolete field
1201 schemaObject.setObsolete( description.isObsolete() );
1202
1203 // The description field
1204 schemaObject.setDescription( description.getDescription() );
1205
1206 // The names field
1207 schemaObject.setNames( description.getNames() );
1208
1209 // The isEnabled field. Has the description does not hold a
1210 // Disable field, we will inherit from the schema enable field
1211 schemaObject.setEnabled( schema.isEnabled() );
1212
1213 // The isReadOnly field. We don't have this data in the description,
1214 // so set it to false
1215 // TODO : should it be a X-READONLY extension ?
1216 schemaObject.setReadOnly( false );
1217
1218 // The specification field
1219 schemaObject.setSpecification( description.getSpecification() );
1220
1221 // The schemaName field
1222 schemaObject.setSchemaName( schema.getSchemaName() );
1223
1224 // The extensions field
1225 schemaObject.setExtensions( description.getExtensions() );
1226 }
1227 }