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; 021 022 023 import java.util.List; 024 import java.util.Map; 025 026 027 /** 028 * Utility class used to generate schema object specifications. Some of the 029 * latest work coming out of the LDAPBIS working body adds optional extensions 030 * to these syntaxes. Descriptions can be generated for 031 * the following objects: 032 * <ul> 033 * <li><a href="./AttributeType.html">AttributeType</a></li> 034 * <li><a href="./DITContentRule.html">DITContentRule</a></li> 035 * <li><a href="./DITContentRule.html">DITStructureRule</a></li> 036 * <li><a href="./LdapComparator.html">Syntax</a></li> 037 * <li><a href="./MatchingRule.html">MatchingRule</a></li> 038 * <li><a href="./MatchingRuleUse.html">MatchingRuleUse</a></li> 039 * <li><a href="./NameForm.html">NameForm</a></li> 040 * <li><a href="./Normalizer.html">Syntax</a></li> 041 * <li><a href="./ObjectClass.html">ObjectClass</a></li> 042 * <li><a href="./LdapSyntax.html">Syntax</a></li> 043 * <li><a href="./SyntaxChecker.html">Syntax</a></li> 044 * </ul> 045 * 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 * @version $Rev: 896579 $ 048 */ 049 public class DescriptionUtils 050 { 051 /** 052 * Generates the description using the AttributeTypeDescription as defined 053 * by the syntax: 1.3.6.1.4.1.1466.115.121.1.3. Only the right hand side of 054 * the description starting at the opening parenthesis is generated: that 055 * is 'AttributeTypeDescription = ' is not generated. 056 * 057 * <pre> 058 * AttributeTypeDescription = "(" whsp 059 * numericoid whsp ; AttributeType identifier 060 * [ "NAME" qdescrs ] ; name used in AttributeType 061 * [ "DESC" qdstring ] ; description 062 * [ "OBSOLETE" whsp ] 063 * [ "SUP" woid ] ; derived from parent AttributeType 064 * [ "EQUALITY" woid ; Matching Rule name 065 * [ "ORDERING" woid ; Matching Rule name 066 * [ "SUBSTR" woid ] ; Matching Rule name 067 * [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3 RFC 2252 068 * [ "SINGLE-VALUE" whsp ] ; default multi-valued 069 * [ "COLLECTIVE" whsp ] ; default not collective 070 * [ "NO-USER-MODIFICATION" whsp ]; default user modifiable 071 * [ "USAGE" whsp AttributeUsage ]; default userApplications 072 * whsp ")" 073 * </pre> 074 * 075 * @param attributeType 076 * the attributeType to generate a description for 077 * @return the AttributeTypeDescription Syntax for the attributeType in a 078 * pretty formated string 079 */ 080 public static String getDescription( AttributeType attributeType ) 081 { 082 StringBuilder buf = new StringBuilder( "( " ); 083 buf.append( attributeType.getOid() ); 084 buf.append( '\n' ); 085 086 if ( attributeType.getNames().size() != 0 ) 087 { 088 buf.append( " NAME " ); 089 getQDescrs( buf, attributeType.getNames() ); 090 } 091 092 if ( attributeType.getDescription() != null ) 093 { 094 buf.append( " DESC " ); 095 buf.append( attributeType.getDescription() ); 096 buf.append( '\n' ); 097 } 098 099 if ( attributeType.isObsolete() ) 100 { 101 buf.append( " OBSOLETE\n" ); 102 } 103 104 if ( attributeType.getSuperior() != null ) 105 { 106 buf.append( " SUP " ); 107 buf.append( attributeType.getSuperiorName() ); 108 buf.append( '\n' ); 109 } 110 111 if ( attributeType.getEquality() != null ) 112 { 113 buf.append( " EQUALITY " ); 114 buf.append( attributeType.getEqualityName() ); 115 buf.append( '\n' ); 116 } 117 118 if ( attributeType.getOrdering() != null ) 119 { 120 buf.append( " ORDERING " ); 121 buf.append( attributeType.getOrderingName() ); 122 buf.append( '\n' ); 123 } 124 125 if ( attributeType.getSubstring() != null ) 126 { 127 buf.append( " SUBSTR " ); 128 buf.append( attributeType.getSubstringName() ); 129 buf.append( '\n' ); 130 } 131 132 if ( attributeType.getSyntax() != null ) 133 { 134 buf.append( " SYNTAX " ); 135 136 buf.append( attributeType.getSyntaxName() ); 137 138 if ( attributeType.getSyntaxLength() > 0 ) 139 { 140 buf.append( '{' ).append( attributeType.getSyntaxLength() ).append( '}' ); 141 } 142 143 buf.append( '\n' ); 144 } 145 146 if ( attributeType.isSingleValued() ) 147 { 148 buf.append( " SINGLE-VALUE\n" ); 149 } 150 151 if ( attributeType.isCollective() ) 152 { 153 buf.append( " COLLECTIVE\n" ); 154 } 155 156 if ( !attributeType.isUserModifiable() ) 157 { 158 buf.append( " NO-USER-MODIFICATION\n" ); 159 } 160 161 buf.append( " USAGE " ); 162 buf.append( UsageEnum.render( attributeType.getUsage() ) ); 163 buf.append( '\n' ); 164 165 if ( attributeType.getExtensions() != null ) 166 { 167 getExtensions( buf, attributeType.getExtensions() ); 168 } 169 170 buf.append( " )\n" ); 171 172 return buf.toString(); 173 } 174 175 176 /** 177 * Generates the ComparatorDescription for a LdapComparator. Only the right 178 * hand side of the description starting at the opening parenthesis is 179 * generated: that is 'ComparatorDescription = ' is not generated. 180 * 181 * <pre> 182 * ComparatorDescription = "(" 183 * numericoid 184 * ["DESC" qdstring ] 185 * "FQCN" whsp fqcn 186 * ["BYTECODE" whsp base64 ] 187 * extensions 188 * ")" 189 * </pre> 190 * 191 * @param comparator 192 * the Comparator to generate the description for 193 * @return the ComparatorDescription string 194 */ 195 public static String getDescription( LdapComparator<?> comparator ) 196 { 197 return getLoadableDescription( comparator ); 198 } 199 200 201 /** 202 * Generates the DITContentRuleDescription for a DITContentRule as defined 203 * by the syntax: 1.3.6.1.4.1.1466.115.121.1.16. Only the right hand side of 204 * the description starting at the opening parenthesis is generated: that 205 * is 'DITContentRuleDescription = ' is not generated. 206 * 207 * <pre> 208 * DITContentRuleDescription = "(" 209 * numericoid ; Structural ObjectClass identifier 210 * [ "NAME" qdescrs ] 211 * [ "DESC" qdstring ] 212 * [ "OBSOLETE" ] 213 * [ "AUX" oids ] ; Auxiliary ObjectClasses 214 * [ "MUST" oids ] ; AttributeType identifiers 215 * [ "MAY" oids ] ; AttributeType identifiers 216 * [ "NOT" oids ] ; AttributeType identifiers 217 * ")" 218 * </pre> 219 * 220 * @param dITContentRule 221 * the DIT content rule specification 222 * @return the specification according to the DITContentRuleDescription 223 * syntax 224 */ 225 public static String getDescription( DITContentRule dITContentRule ) 226 { 227 StringBuilder buf = new StringBuilder( "( " ); 228 buf.append( dITContentRule.getOid() ); 229 buf.append( '\n' ); 230 231 if ( dITContentRule.getNames() != null ) 232 { 233 buf.append( " NAME " ); 234 getQDescrs( buf, dITContentRule.getNames() ); 235 buf.append( '\n' ); 236 } 237 238 if ( dITContentRule.getDescription() != null ) 239 { 240 buf.append( " DESC " ); 241 buf.append( dITContentRule.getDescription() ); 242 buf.append( '\n' ); 243 } 244 245 if ( dITContentRule.isObsolete() ) 246 { 247 buf.append( " OBSOLETE\n" ); 248 } 249 250 // print out all the auxiliary object class oids 251 List<ObjectClass> aux = dITContentRule.getAuxObjectClasses(); 252 253 if ( ( aux != null ) && ( aux.size() > 0 ) ) 254 { 255 buf.append( " AUX " ); 256 getQDStrings( buf, aux ); 257 } 258 259 List<AttributeType> must = dITContentRule.getMustAttributeTypes(); 260 261 if ( ( must != null ) && ( must.size() > 0 ) ) 262 { 263 buf.append( " MUST " ); 264 getQDStrings( buf, must ); 265 } 266 267 List<AttributeType> may = dITContentRule.getMayAttributeTypes(); 268 269 if ( ( may != null ) && ( may.size() > 0 ) ) 270 { 271 buf.append( " MAY " ); 272 getQDStrings( buf, may ); 273 } 274 275 List<AttributeType> not = dITContentRule.getNotAttributeTypes(); 276 277 if ( ( not != null ) && ( not.size() > 0 ) ) 278 { 279 buf.append( " NOT " ); 280 getQDStrings( buf, not ); 281 } 282 283 if ( dITContentRule.getExtensions() != null ) 284 { 285 getExtensions( buf, dITContentRule.getExtensions() ); 286 } 287 288 buf.append( " )\n" ); 289 return buf.toString(); 290 } 291 292 293 /** 294 * Generates the DITStructureRuleDescription for a DITStructureRule as 295 * defined by the syntax: 1.3.6.1.4.1.1466.115.121.1.17. Only the right hand 296 * side of the description starting at the opening parenthesis is 297 * generated: that is 'DITStructureRuleDescription = ' is not generated. 298 * 299 * <pre> 300 * DITStructureRuleDescription = "(" whsp 301 * ruleid ; rule identifier 302 * [ SP "NAME" SP qdescrs ] ; short names (descriptors) 303 * [ SP "DESC" SP qdstring ] ; description 304 * [ SP "OBSOLETE" ] ; not active 305 * SP "FORM" SP oid ; NameForm 306 * [ SP "SUP" ruleids ] ; superior rules 307 * extensions WSP ; extensions 308 * ")" 309 * </pre> 310 * 311 * @param dITStructureRule 312 * the DITStructureRule to generate the description for 313 * @return the description in the DITStructureRuleDescription syntax 314 */ 315 public static String getDescription( DITStructureRule dITStructureRule ) 316 { 317 StringBuilder buf = new StringBuilder( "( " ); 318 buf.append( dITStructureRule.getOid() ); 319 buf.append( '\n' ); 320 321 if ( dITStructureRule.getNames() != null ) 322 { 323 buf.append( " NAME " ); 324 getQDescrs( buf, dITStructureRule.getNames() ); 325 } 326 327 if ( dITStructureRule.getDescription() != null ) 328 { 329 buf.append( " DESC " ); 330 buf.append( dITStructureRule.getDescription() ); 331 buf.append( '\n' ); 332 } 333 334 if ( dITStructureRule.isObsolete() ) 335 { 336 buf.append( " OBSOLETE\n" ); 337 } 338 339 buf.append( " FORM " ); 340 buf.append( dITStructureRule.getForm() ); 341 buf.append( '\n' ); 342 343 // TODO : Shouldn't we get the ruleId OID ? 344 List<Integer> sups = dITStructureRule.getSuperRules(); 345 346 if ( ( sups != null ) && ( sups.size() > 0 ) ) 347 { 348 buf.append( " SUP\n" ); 349 350 if ( sups.size() == 1 ) 351 { 352 buf.append( sups.get( 0 ) ); 353 } 354 else 355 { 356 boolean isFirst = true; 357 buf.append( "( " ); 358 359 for ( int sup : sups ) 360 { 361 if ( isFirst ) 362 { 363 isFirst = false; 364 } 365 else 366 { 367 buf.append( " " ); 368 } 369 370 buf.append( sup ); 371 } 372 373 buf.append( " )" ); 374 } 375 376 buf.append( '\n' ); 377 } 378 379 buf.append( " )\n" ); 380 381 return buf.toString(); 382 } 383 384 385 /** 386 * Generates the MatchingRuleDescription for a MatchingRule as defined by 387 * the syntax: 1.3.6.1.4.1.1466.115.121.1.30. Only the right hand side of 388 * the description starting at the opening parenthesis is generated: that 389 * is 'MatchingRuleDescription = ' is not generated. 390 * 391 * <pre> 392 * MatchingRuleDescription = "(" whsp 393 * numericoid whsp ; MatchingRule object identifier 394 * [ "NAME" qdescrs ] 395 * [ "DESC" qdstring ] 396 * [ "OBSOLETE" whsp ] 397 * "SYNTAX" numericoid 398 * whsp ")" 399 * </pre> 400 * 401 * @param matchingRule 402 * the MatchingRule to generate the description for 403 * @return the MatchingRuleDescription string 404 */ 405 public static String getDescription( MatchingRule matchingRule ) 406 { 407 StringBuilder buf = new StringBuilder( "( " ); 408 buf.append( matchingRule.getOid() ); 409 buf.append( '\n' ); 410 411 if ( matchingRule.getNames() != null ) 412 { 413 buf.append( " NAME " ); 414 getQDescrs( buf, matchingRule.getNames() ); 415 } 416 417 if ( matchingRule.getDescription() != null ) 418 { 419 buf.append( " DESC " ); 420 buf.append( matchingRule.getDescription() ); 421 buf.append( '\n' ); 422 } 423 424 if ( matchingRule.isObsolete() ) 425 { 426 buf.append( " OBSOLETE\n" ); 427 } 428 429 buf.append( " SYNTAX " ); 430 buf.append( matchingRule.getSyntaxOid() ); 431 buf.append( '\n' ); 432 433 if ( matchingRule.getExtensions() != null ) 434 { 435 getExtensions( buf, matchingRule.getExtensions() ); 436 } 437 438 buf.append( " ) " ); 439 return buf.toString(); 440 } 441 442 443 /** 444 * Generates the MatchingRuleUseDescription for a MatchingRuleUse as defined 445 * by the syntax: 1.3.6.1.4.1.1466.115.121.1.31. Only the right hand side of 446 * the description starting at the opening parenthesis is generated: that 447 * is 'MatchingRuleUseDescription = ' is not generated. 448 * 449 * <pre> 450 * MatchingRuleUseDescription = LPAREN WSP 451 * numericoid ; object identifier 452 * [ SP "NAME" SP qdescrs ] ; short names (descriptors) 453 * [ SP "DESC" SP qdstring ] ; description 454 * [ SP "OBSOLETE" ] ; not active 455 * SP "APPLIES" SP oids ; attribute types 456 * extensions WSP RPAREN ; extensions 457 * 458 * where: 459 * [numericoid] is the object identifier of the matching rule 460 * associated with this matching rule use description; 461 * NAME [qdescrs] are short names (descriptors) identifying this 462 * matching rule use; 463 * DESC [qdstring] is a short descriptive string; 464 * OBSOLETE indicates this matching rule use is not active; 465 * APPLIES provides a list of attribute types the matching rule applies 466 * to; and 467 * [extensions] describe extensions. 468 * </pre> 469 * 470 * @param matchingRuleUse The matching rule from which we want to generate 471 * a MatchingRuleUseDescription. 472 * @return The generated MatchingRuleUseDescription 473 */ 474 public static String getDescription( MatchingRuleUse matchingRuleUse ) 475 { 476 StringBuilder buf = new StringBuilder( "( " ); 477 buf.append( matchingRuleUse.getOid() ); 478 buf.append( '\n' ); 479 480 buf.append( " NAME " ); 481 getQDescrs( buf, matchingRuleUse.getNames() ); 482 483 if ( matchingRuleUse.getDescription() != null ) 484 { 485 buf.append( " DESC " ); 486 buf.append( matchingRuleUse.getDescription() ); 487 buf.append( '\n' ); 488 } 489 490 if ( matchingRuleUse.isObsolete() ) 491 { 492 buf.append( " OBSOLETE\n" ); 493 } 494 495 buf.append( " APPLIES " ); 496 List<AttributeType> attributeTypes = matchingRuleUse.getApplicableAttributes(); 497 498 if ( attributeTypes.size() == 1 ) 499 { 500 buf.append( attributeTypes.get( 0 ).getOid() ); 501 } 502 else 503 // for list of oids we need a parenthesis 504 { 505 buf.append( "( " ); 506 507 boolean isFirst = true; 508 509 for ( AttributeType attributeType : attributeTypes ) 510 { 511 if ( isFirst ) 512 { 513 isFirst = false; 514 } 515 else 516 { 517 buf.append( " $ " ); 518 } 519 520 buf.append( attributeType ); 521 } 522 523 buf.append( " ) " ); 524 } 525 526 if ( matchingRuleUse.getExtensions() != null ) 527 { 528 getExtensions( buf, matchingRuleUse.getExtensions() ); 529 } 530 531 buf.append( " )\n" ); 532 533 return buf.toString(); 534 } 535 536 537 /** 538 * Generates the NameFormDescription for a NameForm as defined by the 539 * syntax: 1.3.6.1.4.1.1466.115.121.1.35. Only the right hand side of the 540 * description starting at the opening parenthesis is generated: that is 541 * 'NameFormDescription = ' is not generated. 542 * 543 * <pre> 544 * NameFormDescription = "(" whsp 545 * numericoid whsp ; NameForm identifier 546 * [ "NAME" qdescrs ] 547 * [ "DESC" qdstring ] 548 * [ "OBSOLETE" whsp ] 549 * "OC" woid ; Structural ObjectClass 550 * "MUST" oids ; AttributeTypes 551 * [ "MAY" oids ] ; AttributeTypes 552 * whsp ")" 553 * </pre> 554 * 555 * @param nameForm 556 * the NameForm to generate the description for 557 * @return the NameFormDescription string 558 */ 559 public static String getDescription( NameForm nameForm ) 560 { 561 StringBuilder buf = new StringBuilder( "( " ); 562 buf.append( nameForm.getOid() ); 563 buf.append( '\n' ); 564 565 if ( nameForm.getNames() != null ) 566 { 567 buf.append( " NAME " ); 568 getQDescrs( buf, nameForm.getNames() ); 569 } 570 571 if ( nameForm.getDescription() != null ) 572 { 573 buf.append( " DESC " ); 574 buf.append( nameForm.getDescription() ); 575 buf.append( '\n' ); 576 } 577 578 if ( nameForm.isObsolete() ) 579 { 580 buf.append( " OBSOLETE\n" ); 581 } 582 583 buf.append( " OC " ); 584 buf.append( nameForm.getStructuralObjectClassOid() ); 585 buf.append( '\n' ); 586 587 buf.append( " MUST\n" ); 588 List<AttributeType> must = nameForm.getMustAttributeTypes(); 589 590 getQDStrings( buf, must ); 591 592 List<AttributeType> may = nameForm.getMayAttributeTypes(); 593 594 if ( ( may != null ) && ( may.size() > 0 ) ) 595 { 596 buf.append( " MAY\n" ); 597 getQDStrings( buf, may ); 598 } 599 600 if ( nameForm.getExtensions() != null ) 601 { 602 getExtensions( buf, nameForm.getExtensions() ); 603 } 604 605 buf.append( " )\n" ); 606 return buf.toString(); 607 } 608 609 610 /** 611 * Generates the NormalizerDescription for a Normalizer. Only the right 612 * hand side of the description starting at the opening parenthesis is 613 * generated: that is 'NormalizerDescription = ' is not generated. 614 * 615 * <pre> 616 * NormalizerDescription = "(" 617 * numericoid 618 * ["DESC" qdstring ] 619 * "FQCN" whsp fqcn 620 * ["BYTECODE" whsp base64 ] 621 * extensions 622 * ")" 623 * </pre> 624 * 625 * @param normalizer 626 * the Normalizer to generate the description for 627 * @return the NormalizerDescription string 628 */ 629 public static String getDescription( Normalizer normalizer ) 630 { 631 return getLoadableDescription( normalizer ); 632 } 633 634 635 /** 636 * Generates the ObjectClassDescription for an ObjectClass as defined by the 637 * syntax: 1.3.6.1.4.1.1466.115.121.1.37. Only the right hand side of the 638 * description starting at the opening parenthesis is generated: that is 639 * 'ObjectClassDescription = ' is not generated. 640 * 641 * <pre> 642 * ObjectClassDescription = "(" whsp 643 * numericoid whsp ; ObjectClass identifier 644 * [ "NAME" qdescrs ] 645 * [ "DESC" qdstring ] 646 * [ "OBSOLETE" whsp ] 647 * [ "SUP" oids ] ; Superior ObjectClasses 648 * [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] 649 * ; default structural 650 * [ "MUST" oids ] ; AttributeTypes 651 * [ "MAY" oids ] ; AttributeTypes 652 * whsp ")" 653 * </pre> 654 * 655 * @param objectClass 656 * the ObjectClass to generate a description for 657 * @return the description in the ObjectClassDescription syntax 658 */ 659 public static String getDescription( ObjectClass objectClass ) 660 { 661 StringBuilder buf = new StringBuilder( "( " ); 662 buf.append( objectClass.getOid() ); 663 buf.append( '\n' ); 664 665 if ( ( objectClass.getNames() != null ) && ( objectClass.getNames().size() != 0 ) ) 666 { 667 buf.append( " NAME " ); 668 getQDescrs( buf, objectClass.getNames() ); 669 } 670 671 if ( objectClass.getDescription() != null ) 672 { 673 buf.append( " DESC " ); 674 buf.append( objectClass.getDescription() ); 675 buf.append( '\n' ); 676 } 677 678 if ( objectClass.isObsolete() ) 679 { 680 buf.append( " OBSOLETE\n" ); 681 } 682 683 List<ObjectClass> sups = objectClass.getSuperiors(); 684 685 if ( ( sups != null ) && ( sups.size() > 0 ) ) 686 { 687 buf.append( " SUP " ); 688 getQDStrings( buf, sups ); 689 } 690 691 if ( objectClass.getType() != null ) 692 { 693 buf.append( ' ' ); 694 buf.append( objectClass.getType() ); 695 buf.append( '\n' ); 696 } 697 698 List<AttributeType> must = objectClass.getMustAttributeTypes(); 699 700 if ( ( must != null ) && ( must.size() > 0 ) ) 701 { 702 buf.append( " MUST " ); 703 getQDStrings( buf, must ); 704 } 705 706 List<AttributeType> may = objectClass.getMayAttributeTypes(); 707 708 if ( ( may != null ) && ( may.size() > 0 ) ) 709 { 710 buf.append( " MAY " ); 711 getQDStrings( buf, may ); 712 } 713 714 if ( objectClass.getExtensions() != null ) 715 { 716 getExtensions( buf, objectClass.getExtensions() ); 717 } 718 719 buf.append( " )\n" ); 720 721 return buf.toString(); 722 } 723 724 725 /** 726 * Generates the SyntaxDescription for a Syntax as defined by the syntax: 727 * 1.3.6.1.4.1.1466.115.121.1.54. Only the right hand side of the 728 * description starting at the opening parenthesis is generated: that is 729 * 'SyntaxDescription = ' is not generated. 730 * 731 * <pre> 732 * SyntaxDescription = "(" whsp 733 * numericoid whsp 734 * [ "DESC" qdstring ] 735 * [ extensions ] 736 * whsp ")" 737 * </pre> 738 * 739 * @param syntax 740 * the Syntax to generate a description for 741 * @return the description in the SyntaxDescription syntax 742 */ 743 public static String getDescription( LdapSyntax syntax ) 744 { 745 StringBuilder buf = new StringBuilder( "( " ); 746 buf.append( syntax.getOid() ); 747 buf.append( '\n' ); 748 749 if ( syntax.getDescription() != null ) 750 { 751 buf.append( " DESC " ); 752 buf.append( syntax.getDescription() ); 753 buf.append( '\n' ); 754 } 755 756 if ( syntax.getExtensions() != null ) 757 { 758 getExtensions( buf, syntax.getExtensions() ); 759 } 760 761 buf.append( " )" ); 762 return buf.toString(); 763 } 764 765 766 /** 767 * Generates the SyntaxCheckerDescription for a SyntaxChecker. Only the right 768 * hand side of the description starting at the opening parenthesis is 769 * generated: that is 'SyntaxCheckerDescription = ' is not generated. 770 * 771 * <pre> 772 * SyntaxCheckerDescription = "(" 773 * numericoid 774 * ["DESC" qdstring ] 775 * "FQCN" whsp fqcn 776 * ["BYTECODE" whsp base64 ] 777 * extensions 778 * ")" 779 * </pre> 780 * 781 * @param syntaxChecker 782 * the SyntaxChecker to generate the description for 783 * @return the SyntaxCheckerDescription string 784 */ 785 public static String getDescription( SyntaxChecker syntaxChecker ) 786 { 787 return getLoadableDescription( syntaxChecker ); 788 } 789 790 791 private static void getExtensions( StringBuilder sb, Map<String, List<String>> extensions ) 792 { 793 for ( String key : extensions.keySet() ) 794 { 795 sb.append( key ).append( " " ); 796 797 List<String> values = extensions.get( key ); 798 799 if ( ( values != null ) && ( values.size() != 0 ) ) 800 { 801 if ( values.size() == 1 ) 802 { 803 sb.append( values.get( 0 ) ); 804 } 805 else 806 { 807 boolean isFirst = true; 808 sb.append( "( " ); 809 810 for ( String value : values ) 811 { 812 if ( isFirst ) 813 { 814 isFirst = false; 815 } 816 else 817 { 818 sb.append( " " ); 819 } 820 821 sb.append( value ); 822 } 823 824 sb.append( " )" ); 825 } 826 } 827 828 sb.append( '\n' ); 829 } 830 } 831 832 833 private static void getQDStrings( StringBuilder sb, List<? extends SchemaObject> schemaObjects ) 834 { 835 if ( ( schemaObjects != null ) && ( schemaObjects.size() != 0 ) ) 836 { 837 if ( schemaObjects.size() == 1 ) 838 { 839 sb.append( '\'' ).append( schemaObjects.get( 0 ).getName() ).append( '\'' ); 840 } 841 else 842 { 843 boolean isFirst = true; 844 sb.append( "( " ); 845 846 for ( SchemaObject schemaObject : schemaObjects ) 847 { 848 if ( isFirst ) 849 { 850 isFirst = false; 851 } 852 else 853 { 854 sb.append( " " ); 855 } 856 857 sb.append( '\'' ).append( schemaObject.getName() ).append( '\'' ); 858 } 859 860 sb.append( " )" ); 861 } 862 } 863 864 sb.append( '\n' ); 865 } 866 867 868 private static void getQDescrs( StringBuilder sb, List<String> names ) 869 { 870 if ( ( names != null ) && ( names.size() != 0 ) ) 871 { 872 if ( names.size() == 1 ) 873 { 874 sb.append( '\'' ).append( names.get( 0 ) ).append( '\'' ); 875 } 876 else 877 { 878 boolean isFirst = true; 879 sb.append( "( " ); 880 881 for ( String name : names ) 882 { 883 if ( isFirst ) 884 { 885 isFirst = false; 886 } 887 else 888 { 889 sb.append( " " ); 890 } 891 892 sb.append( '\'' ).append( name ).append( '\'' ); 893 } 894 895 sb.append( " )" ); 896 } 897 } 898 899 sb.append( '\n' ); 900 } 901 902 903 /** 904 * Generate the description for Comparators, Normalizers and SyntaxCheckers. 905 */ 906 private static String getLoadableDescription( LoadableSchemaObject schemaObject ) 907 { 908 StringBuilder buf = new StringBuilder( "( " ); 909 buf.append( schemaObject.getOid() ); 910 buf.append( '\n' ); 911 912 if ( schemaObject.getDescription() != null ) 913 { 914 buf.append( " DESC " ); 915 buf.append( schemaObject.getDescription() ); 916 buf.append( '\n' ); 917 } 918 919 if ( schemaObject.getFqcn() != null ) 920 { 921 buf.append( " FQCN " ); 922 buf.append( schemaObject.getFqcn() ); 923 buf.append( '\n' ); 924 } 925 926 if ( schemaObject.getBytecode() != null ) 927 { 928 buf.append( " BYTECODE " ); 929 930 // We will dump only the 16 first bytes 931 if ( schemaObject.getBytecode().length() > 16 ) 932 { 933 buf.append( schemaObject.getBytecode().substring( 0, 16 ) ); 934 } 935 else 936 { 937 buf.append( schemaObject.getBytecode() ); 938 } 939 940 buf.append( '\n' ); 941 } 942 943 if ( schemaObject.getExtensions() != null ) 944 { 945 getExtensions( buf, schemaObject.getExtensions() ); 946 } 947 948 buf.append( " ) " ); 949 950 return buf.toString(); 951 } 952 }