001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.schema; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.ArrayList; 033 import java.util.HashMap; 034 import java.util.LinkedHashMap; 035 import java.util.LinkedList; 036 import java.util.List; 037 038 import org.opends.server.admin.std.server.*; 039 import org.opends.server.admin.server.ConfigurationChangeListener; 040 import org.opends.server.api.ApproximateMatchingRule; 041 import org.opends.server.api.AttributeSyntax; 042 import org.opends.server.api.EqualityMatchingRule; 043 import org.opends.server.api.OrderingMatchingRule; 044 import org.opends.server.api.SubstringMatchingRule; 045 import org.opends.server.config.ConfigException; 046 import org.opends.server.core.DirectoryServer; 047 048 import static org.opends.server.loggers.debug.DebugLogger.*; 049 import org.opends.server.loggers.debug.DebugTracer; 050 import org.opends.server.types.*; 051 import static org.opends.messages.SchemaMessages.*; 052 053 import org.opends.messages.MessageBuilder; 054 import static org.opends.server.schema.SchemaConstants.*; 055 import static org.opends.server.util.ServerConstants.*; 056 import static org.opends.server.util.StaticUtils.*; 057 058 059 060 /** 061 * This class defines the attribute type description syntax, which is used to 062 * hold attribute type definitions in the server schema. The format of this 063 * syntax is defined in RFC 2252. 064 */ 065 public class AttributeTypeSyntax 066 extends AttributeSyntax<AttributeTypeDescriptionAttributeSyntaxCfg> 067 implements 068 ConfigurationChangeListener<AttributeTypeDescriptionAttributeSyntaxCfg> { 069 070 /** 071 * The tracer object for the debug logger. 072 */ 073 private static final DebugTracer TRACER = getTracer(); 074 075 076 077 // The reference to the configuration for this attribute type description 078 // syntax. 079 private AttributeTypeDescriptionAttributeSyntaxCfg currentConfig; 080 081 082 083 // The default equality matching rule for this syntax. 084 private EqualityMatchingRule defaultEqualityMatchingRule; 085 086 // The default ordering matching rule for this syntax. 087 private OrderingMatchingRule defaultOrderingMatchingRule; 088 089 // The default substring matching rule for this syntax. 090 private SubstringMatchingRule defaultSubstringMatchingRule; 091 092 // If true strip the suggested minimum upper bound from the syntax OID. 093 private static boolean stripMinimumUpperBound=false; 094 095 096 /** 097 * Creates a new instance of this syntax. Note that the only thing that 098 * should be done here is to invoke the default constructor for the 099 * superclass. All initialization should be performed in the 100 * <CODE>initializeSyntax</CODE> method. 101 */ 102 public AttributeTypeSyntax() 103 { 104 super(); 105 } 106 107 108 109 /** 110 * {@inheritDoc} 111 */ 112 public void 113 initializeSyntax(AttributeTypeDescriptionAttributeSyntaxCfg configuration) 114 throws ConfigException, InitializationException 115 { 116 defaultEqualityMatchingRule = 117 DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID); 118 if (defaultEqualityMatchingRule == null) 119 { 120 Message message = ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get( 121 EMR_CASE_IGNORE_OID, SYNTAX_ATTRIBUTE_TYPE_NAME); 122 throw new InitializationException(message); 123 } 124 125 defaultOrderingMatchingRule = 126 DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID); 127 if (defaultOrderingMatchingRule == null) 128 { 129 Message message = ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get( 130 OMR_CASE_IGNORE_OID, SYNTAX_ATTRIBUTE_TYPE_NAME); 131 throw new InitializationException(message); 132 } 133 134 defaultSubstringMatchingRule = 135 DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID); 136 if (defaultSubstringMatchingRule == null) 137 { 138 Message message = ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get( 139 SMR_CASE_IGNORE_OID, SYNTAX_ATTRIBUTE_TYPE_NAME); 140 throw new InitializationException(message); 141 } 142 143 // This syntax is one of the Directory Server's core syntaxes and therefore 144 // it may be instantiated at times without a configuration entry. If that 145 // is the case, then we'll exit now before doing anything that could require 146 // access to that entry. 147 if (configuration == null) 148 { 149 return; 150 } 151 152 currentConfig = configuration; 153 currentConfig.addAttributeTypeDescriptionChangeListener(this); 154 stripMinimumUpperBound=configuration.isStripSyntaxMinUpperBound(); 155 } 156 157 158 159 /** 160 * {@inheritDoc} 161 */ 162 public String getSyntaxName() 163 { 164 return SYNTAX_ATTRIBUTE_TYPE_NAME; 165 } 166 167 168 169 /** 170 * {@inheritDoc} 171 */ 172 public String getOID() 173 { 174 return SYNTAX_ATTRIBUTE_TYPE_OID; 175 } 176 177 178 179 /** 180 * {@inheritDoc} 181 */ 182 public String getDescription() 183 { 184 return SYNTAX_ATTRIBUTE_TYPE_DESCRIPTION; 185 } 186 187 188 189 /** 190 * {@inheritDoc} 191 */ 192 public EqualityMatchingRule getEqualityMatchingRule() 193 { 194 return defaultEqualityMatchingRule; 195 } 196 197 198 199 /** 200 * {@inheritDoc} 201 */ 202 public OrderingMatchingRule getOrderingMatchingRule() 203 { 204 return defaultOrderingMatchingRule; 205 } 206 207 208 209 /** 210 * {@inheritDoc} 211 */ 212 public SubstringMatchingRule getSubstringMatchingRule() 213 { 214 return defaultSubstringMatchingRule; 215 } 216 217 218 219 /** 220 * {@inheritDoc} 221 */ 222 public ApproximateMatchingRule getApproximateMatchingRule() 223 { 224 // There is no approximate matching rule by default. 225 return null; 226 } 227 228 229 230 /** 231 * {@inheritDoc} 232 */ 233 public boolean valueIsAcceptable(ByteString value, 234 MessageBuilder invalidReason) 235 { 236 // We'll use the decodeAttributeType method to determine if the value is 237 // acceptable. 238 try 239 { 240 decodeAttributeType(value, DirectoryServer.getSchema(), true); 241 return true; 242 } 243 catch (DirectoryException de) 244 { 245 if (debugEnabled()) 246 { 247 TRACER.debugCaught(DebugLogLevel.ERROR, de); 248 } 249 250 invalidReason.append(de.getMessageObject()); 251 return false; 252 } 253 } 254 255 256 257 /** 258 * Decodes the contents of the provided ASN.1 octet string as an attribute 259 * type definition according to the rules of this syntax. Note that the 260 * provided octet string value does not need to be normalized (and in fact, it 261 * should not be in order to allow the desired capitalization to be 262 * preserved). 263 * 264 * @param value The ASN.1 octet string containing the value 265 * to decode (it does not need to be 266 * normalized). 267 * @param schema The schema to use to resolve references to 268 * other schema elements. 269 * @param allowUnknownElements Indicates whether to allow values that 270 * reference a superior attribute type which are 271 * not defined in the server schema. This should 272 * only be true when called by 273 * {@code valueIsAcceptable}. 274 * 275 * @return The decoded attribute type definition. 276 * 277 * @throws DirectoryException If the provided value cannot be decoded as an 278 * attribute type definition. 279 */ 280 public static AttributeType decodeAttributeType(ByteString value, 281 Schema schema, 282 boolean allowUnknownElements) 283 throws DirectoryException 284 { 285 // Get string representations of the provided value using the provided form 286 // and with all lowercase characters. 287 String valueStr = value.stringValue(); 288 String lowerStr = toLowerCase(valueStr); 289 290 291 // We'll do this a character at a time. First, skip over any leading 292 // whitespace. 293 int pos = 0; 294 int length = valueStr.length(); 295 while ((pos < length) && (valueStr.charAt(pos) == ' ')) 296 { 297 pos++; 298 } 299 300 if (pos >= length) 301 { 302 // This means that the value was empty or contained only whitespace. That 303 // is illegal. 304 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE.get(); 305 throw new DirectoryException( 306 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 307 } 308 309 310 // The next character must be an open parenthesis. If it is not, then that 311 // is an error. 312 char c = valueStr.charAt(pos++); 313 if (c != '(') 314 { 315 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS.get( 316 valueStr, (pos-1), String.valueOf(c)); 317 throw new DirectoryException( 318 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 319 } 320 321 322 // Skip over any spaces immediately following the opening parenthesis. 323 while ((pos < length) && ((c = valueStr.charAt(pos)) == ' ')) 324 { 325 pos++; 326 } 327 328 if (pos >= length) 329 { 330 // This means that the end of the value was reached before we could find 331 // the OID. Ths is illegal. 332 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 333 throw new DirectoryException( 334 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 335 } 336 337 338 // The next set of characters must be the OID. Strictly speaking, this 339 // should only be a numeric OID, but we'll also allow for the 340 // "attrname-oid" case as well. Look at the first character to figure out 341 // which we will be using. 342 int oidStartPos = pos; 343 if (isDigit(c)) 344 { 345 // This must be a numeric OID. In that case, we will accept only digits 346 // and periods, but not consecutive periods. 347 boolean lastWasPeriod = false; 348 while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' ')) 349 { 350 if (c == '.') 351 { 352 if (lastWasPeriod) 353 { 354 Message message = 355 ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID. 356 get(valueStr, (pos-1)); 357 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 358 message); 359 } 360 else 361 { 362 lastWasPeriod = true; 363 } 364 } 365 else if (! isDigit(c)) 366 { 367 // This must have been an illegal character. 368 Message message = 369 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. 370 get(valueStr, String.valueOf(c), (pos-1)); 371 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 372 message); 373 } 374 else 375 { 376 lastWasPeriod = false; 377 } 378 } 379 } 380 else 381 { 382 // This must be a "fake" OID. In this case, we will only accept 383 // alphabetic characters, numeric digits, and the hyphen. 384 while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' ')) 385 { 386 if (isAlpha(c) || isDigit(c) || (c == '-') || 387 ((c == '_') && DirectoryServer.allowAttributeNameExceptions())) 388 { 389 // This is fine. It is an acceptable character. 390 } 391 else 392 { 393 // This must have been an illegal character. 394 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID. 395 get(valueStr, String.valueOf(c), (pos-1)); 396 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 397 message); 398 } 399 } 400 } 401 402 403 // If we're at the end of the value, then it isn't a valid attribute type 404 // description. Otherwise, parse out the OID. 405 String oid; 406 if (pos >= length) 407 { 408 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 409 throw new DirectoryException( 410 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 411 } 412 else 413 { 414 oid = lowerStr.substring(oidStartPos, (pos-1)); 415 } 416 417 418 // Skip over the space(s) after the OID. 419 while ((pos < length) && ((c = valueStr.charAt(pos)) == ' ')) 420 { 421 pos++; 422 } 423 424 if (pos >= length) 425 { 426 // This means that the end of the value was reached before we could find 427 // the OID. Ths is illegal. 428 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 429 throw new DirectoryException( 430 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 431 } 432 433 434 // At this point, we should have a pretty specific syntax that describes 435 // what may come next, but some of the components are optional and it would 436 // be pretty easy to put something in the wrong order, so we will be very 437 // flexible about what we can accept. Just look at the next token, figure 438 // out what it is and how to treat what comes after it, then repeat until 439 // we get to the end of the value. But before we start, set default values 440 // for everything else we might need to know. 441 String primaryName = oid; 442 List<String> typeNames = new LinkedList<String>(); 443 String description = null; 444 AttributeType superiorType = null; 445 AttributeSyntax syntax = DirectoryServer.getDefaultAttributeSyntax(); 446 ApproximateMatchingRule approximateMatchingRule = null; 447 EqualityMatchingRule equalityMatchingRule = null; 448 OrderingMatchingRule orderingMatchingRule = null; 449 SubstringMatchingRule substringMatchingRule = null; 450 AttributeUsage attributeUsage = AttributeUsage.USER_APPLICATIONS; 451 boolean isCollective = false; 452 boolean isNoUserModification = false; 453 boolean isObsolete = false; 454 boolean isSingleValue = false; 455 HashMap<String,List<String>> extraProperties = 456 new LinkedHashMap<String,List<String>>(); 457 458 459 while (true) 460 { 461 StringBuilder tokenNameBuffer = new StringBuilder(); 462 pos = readTokenName(valueStr, tokenNameBuffer, pos); 463 String tokenName = tokenNameBuffer.toString(); 464 String lowerTokenName = toLowerCase(tokenName); 465 if (tokenName.equals(")")) 466 { 467 // We must be at the end of the value. If not, then that's a problem. 468 if (pos < length) 469 { 470 Message message = 471 ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS. 472 get(valueStr, (pos-1)); 473 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 474 message); 475 } 476 477 break; 478 } 479 else if (lowerTokenName.equals("name")) 480 { 481 // This specifies the set of names for the attribute type. It may be a 482 // single name in single quotes, or it may be an open parenthesis 483 // followed by one or more names in single quotes separated by spaces. 484 c = valueStr.charAt(pos++); 485 if (c == '\'') 486 { 487 StringBuilder userBuffer = new StringBuilder(); 488 StringBuilder lowerBuffer = new StringBuilder(); 489 pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer, 490 (pos-1)); 491 primaryName = userBuffer.toString(); 492 typeNames.add(primaryName); 493 } 494 else if (c == '(') 495 { 496 StringBuilder userBuffer = new StringBuilder(); 497 StringBuilder lowerBuffer = new StringBuilder(); 498 pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer, 499 pos); 500 primaryName = userBuffer.toString(); 501 typeNames.add(primaryName); 502 503 504 while (true) 505 { 506 if (valueStr.charAt(pos) == ')') 507 { 508 // Skip over any spaces after the parenthesis. 509 pos++; 510 while ((pos < length) && ((c = valueStr.charAt(pos)) == ' ')) 511 { 512 pos++; 513 } 514 515 break; 516 } 517 else 518 { 519 userBuffer = new StringBuilder(); 520 lowerBuffer = new StringBuilder(); 521 522 pos = readQuotedString(valueStr, lowerStr, userBuffer, 523 lowerBuffer, pos); 524 typeNames.add(userBuffer.toString()); 525 } 526 } 527 } 528 else 529 { 530 // This is an illegal character. 531 Message message = 532 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR.get( 533 valueStr, String.valueOf(c), (pos-1)); 534 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 535 message); 536 } 537 } 538 else if (lowerTokenName.equals("desc")) 539 { 540 // This specifies the description for the attribute type. It is an 541 // arbitrary string of characters enclosed in single quotes. 542 StringBuilder descriptionBuffer = new StringBuilder(); 543 pos = readQuotedString(valueStr, descriptionBuffer, pos); 544 description = descriptionBuffer.toString(); 545 } 546 else if (lowerTokenName.equals("obsolete")) 547 { 548 // This indicates whether the attribute type should be considered 549 // obsolete. We do not need to do any more parsing for this token. 550 isObsolete = true; 551 } 552 else if (lowerTokenName.equals("sup")) 553 { 554 // This specifies the name or OID of the superior attribute type from 555 // which this attribute type should inherit its properties. 556 StringBuilder woidBuffer = new StringBuilder(); 557 pos = readWOID(lowerStr, woidBuffer, pos); 558 superiorType = schema.getAttributeType(woidBuffer.toString()); 559 if (superiorType == null) 560 { 561 if (allowUnknownElements) 562 { 563 superiorType = DirectoryServer.getDefaultAttributeType( 564 woidBuffer.toString()); 565 } 566 else 567 { 568 // This is bad because we don't know what the superior attribute 569 // type is so we can't base this attribute type on it. 570 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE. 571 get(String.valueOf(oid), String.valueOf(woidBuffer)); 572 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 573 message); 574 } 575 } 576 577 578 // Use the information in the superior type to provide defaults for the 579 // rest of the components in this attribute type description. 580 // Technically, the definition of the superior type should be provided 581 // before the matching rule, syntax, single-value, collective, 582 // no-user-modification, and usage components, and in that case we won't 583 // undo something else that has already been set by an earlier 584 // definition. However, if the information is provided out-of-order, 585 // then it is possible that this could overwrite some desired setting 586 // that is different from that of the supertype. 587 approximateMatchingRule = superiorType.getApproximateMatchingRule(); 588 equalityMatchingRule = superiorType.getEqualityMatchingRule(); 589 orderingMatchingRule = superiorType.getOrderingMatchingRule(); 590 substringMatchingRule = superiorType.getSubstringMatchingRule(); 591 syntax = superiorType.getSyntax(); 592 isSingleValue = superiorType.isSingleValue(); 593 isCollective = superiorType.isCollective(); 594 isNoUserModification = superiorType.isNoUserModification(); 595 attributeUsage = superiorType.getUsage(); 596 } 597 else if (lowerTokenName.equals("equality")) 598 { 599 // This specifies the name or OID of the equality matching rule to use 600 // for this attribute type. 601 StringBuilder woidBuffer = new StringBuilder(); 602 pos = readWOID(lowerStr, woidBuffer, pos); 603 EqualityMatchingRule emr = 604 schema.getEqualityMatchingRule(woidBuffer.toString()); 605 if (emr == null) 606 { 607 // This is bad because we have no idea what the equality matching 608 // rule should be. 609 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR.get( 610 String.valueOf(oid), String.valueOf(woidBuffer)); 611 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 612 message); 613 } 614 else 615 { 616 equalityMatchingRule = emr; 617 } 618 } 619 else if (lowerTokenName.equals("ordering")) 620 { 621 // This specifies the name or OID of the ordering matching rule to use 622 // for this attribute type. 623 StringBuilder woidBuffer = new StringBuilder(); 624 pos = readWOID(lowerStr, woidBuffer, pos); 625 OrderingMatchingRule omr = 626 schema.getOrderingMatchingRule(woidBuffer.toString()); 627 if (omr == null) 628 { 629 // This is bad because we have no idea what the ordering matching 630 // rule should be. 631 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR.get( 632 String.valueOf(oid), String.valueOf(woidBuffer)); 633 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 634 message); 635 } 636 else 637 { 638 orderingMatchingRule = omr; 639 } 640 } 641 else if (lowerTokenName.equals("substr")) 642 { 643 // This specifies the name or OID of the substring matching rule to use 644 // for this attribute type. 645 StringBuilder woidBuffer = new StringBuilder(); 646 pos = readWOID(lowerStr, woidBuffer, pos); 647 SubstringMatchingRule smr = 648 schema.getSubstringMatchingRule(woidBuffer.toString()); 649 if (smr == null) 650 { 651 // This is bad because we have no idea what the substring matching 652 // rule should be. 653 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR.get( 654 String.valueOf(oid), String.valueOf(woidBuffer)); 655 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 656 message); 657 } 658 else 659 { 660 substringMatchingRule = smr; 661 } 662 } 663 else if (lowerTokenName.equals("syntax")) 664 { 665 // This specifies the numeric OID of the syntax for this matching rule. 666 // It may optionally be immediately followed by an open curly brace, an 667 // integer value, and a close curly brace to suggest the minimum number 668 // of characters that should be allowed in values of that type. This 669 // implementation will ignore any such length because it does not 670 // impose any practical limit on the length of attribute values. 671 boolean inBrace = false; 672 boolean lastWasPeriod = false; 673 StringBuilder oidBuffer = new StringBuilder(); 674 while (pos < length) 675 { 676 c = lowerStr.charAt(pos++); 677 if (inBrace) 678 { 679 // The only thing we'll allow here will be numeric digits and the 680 // closing curly brace. 681 if (c == '}') 682 { 683 // The next character must be a space. 684 if ((c = lowerStr.charAt(pos)) != ' ') 685 { 686 Message message = 687 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. 688 get(valueStr, String.valueOf(c), (pos-1)); 689 throw new DirectoryException( 690 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 691 } 692 693 break; 694 } 695 else if (! isDigit(c)) 696 { 697 Message message = 698 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. 699 get(valueStr, String.valueOf(c), (pos-1)); 700 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 701 message); 702 } 703 } 704 else 705 { 706 if (isDigit(c)) 707 { 708 oidBuffer.append(c); 709 lastWasPeriod = false; 710 } 711 else if (c == '.') 712 { 713 if (lastWasPeriod) 714 { 715 Message message = 716 ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID. 717 get(valueStr, (pos-1)); 718 throw new DirectoryException( 719 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 720 } 721 else 722 { 723 oidBuffer.append(c); 724 lastWasPeriod = true; 725 } 726 } 727 else if (c == '{') 728 { 729 // It's the start of the length specification. 730 inBrace = true; 731 } 732 else if (c == ' ') 733 { 734 // It's the end of the value. 735 break; 736 } 737 else 738 { 739 Message message = 740 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. 741 get(valueStr, String.valueOf(c), (pos-1)); 742 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 743 message); 744 } 745 } 746 } 747 748 syntax = schema.getSyntax(oidBuffer.toString()); 749 if (syntax == null) 750 { 751 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX.get( 752 String.valueOf(oid), String.valueOf(oidBuffer)); 753 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 754 message); 755 } 756 757 if (approximateMatchingRule == null) 758 { 759 approximateMatchingRule = syntax.getApproximateMatchingRule(); 760 } 761 762 if (equalityMatchingRule == null) 763 { 764 equalityMatchingRule = syntax.getEqualityMatchingRule(); 765 } 766 767 if (orderingMatchingRule == null) 768 { 769 orderingMatchingRule = syntax.getOrderingMatchingRule(); 770 } 771 772 if (substringMatchingRule == null) 773 { 774 substringMatchingRule = syntax.getSubstringMatchingRule(); 775 } 776 } 777 else if (lowerTokenName.equals("single-value")) 778 { 779 // This indicates that attributes of this type are allowed to have at 780 // most one value. We do not need any more parsing for this token. 781 isSingleValue = true; 782 } 783 else if (lowerTokenName.equals("collective")) 784 { 785 // This indicates that attributes of this type are collective (i.e., 786 // have their values generated dynamically in some way). We do not need 787 // any more parsing for this token. 788 isCollective = true; 789 } 790 else if (lowerTokenName.equals("no-user-modification")) 791 { 792 // This indicates that the values of attributes of this type are not to 793 // be modified by end users. We do not need any more parsing for this 794 // token. 795 isNoUserModification = true; 796 } 797 else if (lowerTokenName.equals("usage")) 798 { 799 // This specifies the usage string for this attribute type. It should 800 // be followed by one of the strings "userApplications", 801 // "directoryOperation", "distributedOperation", or "dSAOperation". 802 StringBuilder usageBuffer = new StringBuilder(); 803 while (pos < length) 804 { 805 c = lowerStr.charAt(pos++); 806 if (c == ' ') 807 { 808 break; 809 } 810 else 811 { 812 usageBuffer.append(c); 813 } 814 } 815 816 String usageStr = usageBuffer.toString(); 817 if (usageStr.equals("userapplications")) 818 { 819 attributeUsage = AttributeUsage.USER_APPLICATIONS; 820 } 821 else if (usageStr.equals("directoryoperation")) 822 { 823 attributeUsage = AttributeUsage.DIRECTORY_OPERATION; 824 } 825 else if (usageStr.equals("distributedoperation")) 826 { 827 attributeUsage = AttributeUsage.DISTRIBUTED_OPERATION; 828 } 829 else if (usageStr.equals("dsaoperation")) 830 { 831 attributeUsage = AttributeUsage.DSA_OPERATION; 832 } 833 else 834 { 835 // This must be an illegal usage. 836 attributeUsage = AttributeUsage.USER_APPLICATIONS; 837 838 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE. 839 get(String.valueOf(oid), usageStr); 840 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 841 message); 842 } 843 } 844 else 845 { 846 // This must be a non-standard property and it must be followed by 847 // either a single value in single quotes or an open parenthesis 848 // followed by one or more values in single quotes separated by spaces 849 // followed by a close parenthesis. 850 List<String> valueList = new ArrayList<String>(); 851 pos = readExtraParameterValues(valueStr, valueList, pos); 852 extraProperties.put(tokenName, valueList); 853 } 854 } 855 856 List<String> approxRules = extraProperties.get(SCHEMA_PROPERTY_APPROX_RULE); 857 if ((approxRules != null) && (! approxRules.isEmpty())) 858 { 859 String ruleName = approxRules.get(0); 860 String lowerName = toLowerCase(ruleName); 861 ApproximateMatchingRule amr = 862 schema.getApproximateMatchingRule(lowerName); 863 if (amr == null) 864 { 865 // This is bad because we have no idea what the approximate matching 866 // rule should be. 867 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR.get( 868 String.valueOf(oid), String.valueOf(ruleName)); 869 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 870 } 871 else 872 { 873 approximateMatchingRule = amr; 874 } 875 } 876 877 878 // If there is a superior type, then it must have the same usage as the 879 // subordinate type. Also, if the superior type is collective, then so must 880 // the subordinate type be collective. 881 if (superiorType != null) 882 { 883 if (superiorType.getUsage() != attributeUsage) 884 { 885 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE.get( 886 oid, String.valueOf(attributeUsage), superiorType.getNameOrOID()); 887 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 888 } 889 890 if (superiorType.isCollective() != isCollective) 891 { 892 Message message; 893 if (isCollective) 894 { 895 message = WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE.get( 896 oid, superiorType.getNameOrOID()); 897 } 898 else 899 { 900 message = 901 WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE.get( 902 oid, superiorType.getNameOrOID()); 903 } 904 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 905 } 906 } 907 908 909 // If the attribute type is COLLECTIVE, then it must have a usage of 910 // userApplications. 911 if (isCollective && (attributeUsage != AttributeUsage.USER_APPLICATIONS)) 912 { 913 Message message = 914 WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL.get(oid); 915 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 916 } 917 918 919 // If the attribute type is NO-USER-MODIFICATION, then it must not have a 920 // usage of userApplications. 921 if (isNoUserModification && 922 (attributeUsage == AttributeUsage.USER_APPLICATIONS)) 923 { 924 Message message = 925 WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL.get(oid); 926 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); 927 } 928 929 930 return new AttributeType(value.stringValue(), primaryName, typeNames, oid, 931 description, superiorType, syntax, 932 approximateMatchingRule, equalityMatchingRule, 933 orderingMatchingRule, substringMatchingRule, 934 attributeUsage, isCollective, isNoUserModification, 935 isObsolete, isSingleValue, extraProperties); 936 } 937 938 939 940 /** 941 * Reads the next token name from the attribute type definition, skipping over 942 * any leading or trailing spaces, and appends it to the provided buffer. 943 * 944 * @param valueStr The string representation of the attribute type 945 * definition. 946 * @param tokenName The buffer into which the token name will be written. 947 * @param startPos The position in the provided string at which to start 948 * reading the token name. 949 * 950 * @return The position of the first character that is not part of the token 951 * name or one of the trailing spaces after it. 952 * 953 * @throws DirectoryException If a problem is encountered while reading the 954 * token name. 955 */ 956 private static int readTokenName(String valueStr, StringBuilder tokenName, 957 int startPos) 958 throws DirectoryException 959 { 960 // Skip over any spaces at the beginning of the value. 961 char c = '\u0000'; 962 int length = valueStr.length(); 963 while ((startPos < length) && ((c = valueStr.charAt(startPos)) == ' ')) 964 { 965 startPos++; 966 } 967 968 if (startPos >= length) 969 { 970 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 971 throw new DirectoryException( 972 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 973 } 974 975 976 // Read until we find the next space. 977 while ((startPos < length) && ((c = valueStr.charAt(startPos++)) != ' ')) 978 { 979 tokenName.append(c); 980 } 981 982 983 // Skip over any trailing spaces after the value. 984 while ((startPos < length) && ((c = valueStr.charAt(startPos)) == ' ')) 985 { 986 startPos++; 987 } 988 989 990 // Return the position of the first non-space character after the token. 991 return startPos; 992 } 993 994 995 996 /** 997 * Reads the value of a string enclosed in single quotes, skipping over the 998 * quotes and any leading or trailing spaces, and appending the string to the 999 * provided buffer. 1000 * 1001 * @param valueStr The user-provided representation of the attribute type 1002 * definition. 1003 * @param valueBuffer The buffer into which the user-provided representation 1004 * of the value will be placed. 1005 * @param startPos The position in the provided string at which to start 1006 * reading the quoted string. 1007 * 1008 * @return The position of the first character that is not part of the quoted 1009 * string or one of the trailing spaces after it. 1010 * 1011 * @throws DirectoryException If a problem is encountered while reading the 1012 * quoted string. 1013 */ 1014 private static int readQuotedString(String valueStr, 1015 StringBuilder valueBuffer, int startPos) 1016 throws DirectoryException 1017 { 1018 // Skip over any spaces at the beginning of the value. 1019 char c = '\u0000'; 1020 int length = valueStr.length(); 1021 while ((startPos < length) && ((c = valueStr.charAt(startPos)) == ' ')) 1022 { 1023 startPos++; 1024 } 1025 1026 if (startPos >= length) 1027 { 1028 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 1029 throw new DirectoryException( 1030 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1031 } 1032 1033 1034 // The next character must be a single quote. 1035 if (c != '\'') 1036 { 1037 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS.get( 1038 valueStr, startPos, String.valueOf(c)); 1039 throw new DirectoryException( 1040 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1041 } 1042 1043 1044 // Read until we find the closing quote. 1045 startPos++; 1046 while ((startPos < length) && ((c = valueStr.charAt(startPos)) != '\'')) 1047 { 1048 valueBuffer.append(c); 1049 startPos++; 1050 } 1051 1052 1053 // Skip over any trailing spaces after the value. 1054 startPos++; 1055 while ((startPos < length) && ((c = valueStr.charAt(startPos)) == ' ')) 1056 { 1057 startPos++; 1058 } 1059 1060 1061 // If we're at the end of the value, then that's illegal. 1062 if (startPos >= length) 1063 { 1064 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 1065 throw new DirectoryException( 1066 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1067 } 1068 1069 1070 // Return the position of the first non-space character after the token. 1071 return startPos; 1072 } 1073 1074 1075 1076 /** 1077 * Reads the value of a string enclosed in single quotes, skipping over the 1078 * quotes and any leading or trailing spaces, and appending the string to the 1079 * provided buffer. 1080 * 1081 * @param valueStr The user-provided representation of the attribute type 1082 * definition. 1083 * @param lowerStr The all-lowercase representation of the attribute type 1084 * definition. 1085 * @param userBuffer The buffer into which the user-provided representation 1086 * of the value will be placed. 1087 * @param lowerBuffer The buffer into which the all-lowercase representation 1088 * of the value will be placed. 1089 * @param startPos The position in the provided string at which to start 1090 * reading the quoted string. 1091 * 1092 * @return The position of the first character that is not part of the quoted 1093 * string or one of the trailing spaces after it. 1094 * 1095 * @throws DirectoryException If a problem is encountered while reading the 1096 * quoted string. 1097 */ 1098 private static int readQuotedString(String valueStr, String lowerStr, 1099 StringBuilder userBuffer, 1100 StringBuilder lowerBuffer, int startPos) 1101 throws DirectoryException 1102 { 1103 // Skip over any spaces at the beginning of the value. 1104 char c = '\u0000'; 1105 int length = lowerStr.length(); 1106 while ((startPos < length) && ((c = lowerStr.charAt(startPos)) == ' ')) 1107 { 1108 startPos++; 1109 } 1110 1111 if (startPos >= length) 1112 { 1113 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(lowerStr); 1114 throw new DirectoryException( 1115 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1116 } 1117 1118 1119 // The next character must be a single quote. 1120 if (c != '\'') 1121 { 1122 Message message = WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS.get( 1123 valueStr, startPos, String.valueOf(c)); 1124 throw new DirectoryException( 1125 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1126 } 1127 1128 1129 // Read until we find the closing quote. 1130 startPos++; 1131 while ((startPos < length) && ((c = lowerStr.charAt(startPos)) != '\'')) 1132 { 1133 lowerBuffer.append(c); 1134 userBuffer.append(valueStr.charAt(startPos)); 1135 startPos++; 1136 } 1137 1138 1139 // Skip over any trailing spaces after the value. 1140 startPos++; 1141 while ((startPos < length) && ((c = lowerStr.charAt(startPos)) == ' ')) 1142 { 1143 startPos++; 1144 } 1145 1146 1147 // If we're at the end of the value, then that's illegal. 1148 if (startPos >= length) 1149 { 1150 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(lowerStr); 1151 throw new DirectoryException( 1152 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1153 } 1154 1155 1156 // Return the position of the first non-space character after the token. 1157 return startPos; 1158 } 1159 1160 1161 1162 /** 1163 * Reads the attribute description or numeric OID from the provided string, 1164 * skipping over any leading or trailing spaces, and appending the value to 1165 * the provided buffer. 1166 * 1167 * @param lowerStr The string from which the name or OID is to be read. 1168 * @param woidBuffer The buffer into which the name or OID should be 1169 * appended. 1170 * @param startPos The position at which to start reading. 1171 * 1172 * @return The position of the first character after the name or OID that is 1173 * not a space. 1174 * 1175 * @throws DirectoryException If a problem is encountered while reading the 1176 * name or OID. 1177 */ 1178 private static int readWOID(String lowerStr, StringBuilder woidBuffer, 1179 int startPos) 1180 throws DirectoryException 1181 { 1182 // Skip over any spaces at the beginning of the value. 1183 char c = '\u0000'; 1184 int length = lowerStr.length(); 1185 while ((startPos < length) && ((c = lowerStr.charAt(startPos)) == ' ')) 1186 { 1187 startPos++; 1188 } 1189 1190 if (startPos >= length) 1191 { 1192 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(lowerStr); 1193 throw new DirectoryException( 1194 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1195 } 1196 1197 1198 // The next character must be either numeric (for an OID) or alphabetic (for 1199 // an attribute description). 1200 if (isDigit(c)) 1201 { 1202 // This must be a numeric OID. In that case, we will accept only digits 1203 // and periods, but not consecutive periods. 1204 boolean lastWasPeriod = false; 1205 while ((startPos < length) && ((c = lowerStr.charAt(startPos++)) != ' ')) 1206 { 1207 if (c == '.') 1208 { 1209 if (lastWasPeriod) 1210 { 1211 Message message = 1212 ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID. 1213 get(lowerStr, (startPos-1)); 1214 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 1215 message); 1216 } 1217 else 1218 { 1219 woidBuffer.append(c); 1220 lastWasPeriod = true; 1221 } 1222 } 1223 else if (! isDigit(c)) 1224 { 1225 // Technically, this must be an illegal character. However, it is 1226 // possible that someone just got sloppy and did not include a space 1227 // between the name/OID and a closing parenthesis. In that case, 1228 // we'll assume it's the end of the value. What's more, we'll have 1229 // to prematurely return to nasty side effects from stripping off 1230 // additional characters. 1231 if (c == ')') 1232 { 1233 return (startPos-1); 1234 } 1235 1236 // This must have been an illegal character. 1237 Message message = 1238 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. 1239 get(lowerStr, String.valueOf(c), (startPos-1)); 1240 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 1241 message); 1242 } 1243 else 1244 { 1245 woidBuffer.append(c); 1246 lastWasPeriod = false; 1247 } 1248 } 1249 } 1250 else if (isAlpha(c)) 1251 { 1252 // This must be an attribute description. In this case, we will only 1253 // accept alphabetic characters, numeric digits, and the hyphen. 1254 while ((startPos < length) && ((c = lowerStr.charAt(startPos++)) != ' ')) 1255 { 1256 if (isAlpha(c) || isDigit(c) || (c == '-') || 1257 ((c == '_') && DirectoryServer.allowAttributeNameExceptions())) 1258 { 1259 woidBuffer.append(c); 1260 } 1261 else 1262 { 1263 // Technically, this must be an illegal character. However, it is 1264 // possible that someone just got sloppy and did not include a space 1265 // between the name/OID and a closing parenthesis. In that case, 1266 // we'll assume it's the end of the value. What's more, we'll have 1267 // to prematurely return to nasty side effects from stripping off 1268 // additional characters. 1269 if (c == ')') 1270 { 1271 return (startPos-1); 1272 } 1273 1274 // This must have been an illegal character. 1275 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID. 1276 get(lowerStr, String.valueOf(c), (startPos-1)); 1277 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 1278 message); 1279 } 1280 } 1281 } 1282 else 1283 { 1284 Message message = 1285 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR. 1286 get(lowerStr, String.valueOf(c), startPos); 1287 throw new DirectoryException( 1288 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1289 } 1290 1291 1292 // Skip over any trailing spaces after the value. 1293 while ((startPos < length) && ((c = lowerStr.charAt(startPos)) == ' ')) 1294 { 1295 startPos++; 1296 } 1297 1298 1299 // If we're at the end of the value, then that's illegal. 1300 if (startPos >= length) 1301 { 1302 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(lowerStr); 1303 throw new DirectoryException( 1304 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1305 } 1306 1307 1308 // Return the position of the first non-space character after the token. 1309 return startPos; 1310 } 1311 1312 1313 1314 /** 1315 * Reads the value for an "extra" parameter. It will handle a single unquoted 1316 * word (which is technically illegal, but we'll allow it), a single quoted 1317 * string, or an open parenthesis followed by a space-delimited set of quoted 1318 * strings or unquoted words followed by a close parenthesis. 1319 * 1320 * @param valueStr The string containing the information to be read. 1321 * @param valueList The list of "extra" parameter values read so far. 1322 * @param startPos The position in the value string at which to start 1323 * reading. 1324 * 1325 * @return The "extra" parameter value that was read. 1326 * 1327 * @throws DirectoryException If a problem occurs while attempting to read 1328 * the value. 1329 */ 1330 private static int readExtraParameterValues(String valueStr, 1331 List<String> valueList, int startPos) 1332 throws DirectoryException 1333 { 1334 // Skip over any leading spaces. 1335 int length = valueStr.length(); 1336 char c = valueStr.charAt(startPos++); 1337 while ((startPos < length) && (c == ' ')) 1338 { 1339 c = valueStr.charAt(startPos++); 1340 } 1341 1342 if (startPos >= length) 1343 { 1344 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 1345 throw new DirectoryException( 1346 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1347 } 1348 1349 1350 // Look at the next character. If it is a quote, then parse until the next 1351 // quote and end. If it is an open parenthesis, then parse individual 1352 // values until the close parenthesis and end. Otherwise, parse until the 1353 // next space and end. 1354 if (c == '\'') 1355 { 1356 // Parse until the closing quote. 1357 StringBuilder valueBuffer = new StringBuilder(); 1358 while ((startPos < length) && ((c = valueStr.charAt(startPos++)) != '\'')) 1359 { 1360 valueBuffer.append(c); 1361 } 1362 1363 valueList.add(valueBuffer.toString()); 1364 } 1365 else if (c == '(') 1366 { 1367 while (true) 1368 { 1369 // Skip over any leading spaces; 1370 startPos++; 1371 while ((startPos < length) && ((c = valueStr.charAt(startPos)) == ' ')) 1372 { 1373 startPos++; 1374 } 1375 1376 if (startPos >= length) 1377 { 1378 Message message = 1379 ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 1380 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 1381 message); 1382 } 1383 1384 1385 if (c == ')') 1386 { 1387 // This is the end of the list. 1388 break; 1389 } 1390 else if (c == '(') 1391 { 1392 // This is an illegal character. 1393 Message message = 1394 ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR.get( 1395 valueStr, String.valueOf(c), startPos); 1396 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 1397 message); 1398 } 1399 else 1400 { 1401 // We'll recursively call this method to deal with this. 1402 startPos = readExtraParameterValues(valueStr, valueList, startPos); 1403 } 1404 } 1405 } 1406 else 1407 { 1408 // Parse until the next space. 1409 StringBuilder valueBuffer = new StringBuilder(); 1410 while ((startPos < length) && ((c = valueStr.charAt(startPos++)) != ' ')) 1411 { 1412 valueBuffer.append(c); 1413 } 1414 1415 valueList.add(valueBuffer.toString()); 1416 } 1417 1418 1419 1420 // Skip over any trailing spaces. 1421 while ((startPos < length) && (valueStr.charAt(startPos) == ' ')) 1422 { 1423 startPos++; 1424 } 1425 1426 if (startPos >= length) 1427 { 1428 Message message = ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE.get(valueStr); 1429 throw new DirectoryException( 1430 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 1431 } 1432 1433 1434 return startPos; 1435 } 1436 1437 1438 1439 /** 1440 * {@inheritDoc} 1441 */ 1442 public ConfigChangeResult applyConfigurationChange( 1443 AttributeTypeDescriptionAttributeSyntaxCfg configuration) 1444 { 1445 currentConfig = configuration; 1446 stripMinimumUpperBound = configuration.isStripSyntaxMinUpperBound(); 1447 1448 return new ConfigChangeResult(ResultCode.SUCCESS, false); 1449 } 1450 1451 1452 1453 /** 1454 * {@inheritDoc} 1455 */ 1456 public boolean isConfigurationChangeAcceptable( 1457 AttributeTypeDescriptionAttributeSyntaxCfg configuration, 1458 List<Message> unacceptableReasons) 1459 { 1460 // The configuration will always be acceptable. 1461 return true; 1462 } 1463 1464 /** 1465 * Boolean that indicates that the minimum upper bound value should be 1466 * stripped from the Attrbute Type Syntax Description. 1467 * 1468 * @return True if the minimum upper bound value should be stripped. 1469 */ 1470 public static boolean isStripSyntaxMinimumUpperBound() { 1471 return stripMinimumUpperBound; 1472 } 1473 1474 } 1475