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 }