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