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