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