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.types; 028 029 030 031 import java.util.Iterator; 032 import java.util.LinkedHashMap; 033 import java.util.LinkedHashSet; 034 import java.util.LinkedList; 035 import java.util.List; 036 import java.util.Map; 037 import java.util.Set; 038 039 import org.opends.server.schema.DITStructureRuleSyntax; 040 041 import static org.opends.server.loggers.debug.DebugLogger.*; 042 import org.opends.server.loggers.debug.DebugTracer; 043 import static org.opends.server.util.ServerConstants.*; 044 import static org.opends.server.util.Validator.*; 045 046 047 048 /** 049 * This class defines a DIT structure rule, which is used to indicate 050 * the types of children that entries may have. 051 */ 052 @org.opends.server.types.PublicAPI( 053 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 054 mayInstantiate=false, 055 mayExtend=false, 056 mayInvoke=true) 057 public final class DITStructureRule 058 implements SchemaFileElement 059 { 060 /** 061 * The tracer object for the debug logger. 062 */ 063 private static final DebugTracer TRACER = getTracer(); 064 065 // Indicates whether this DIT structure rule is declared "obsolete". 066 private final boolean isObsolete; 067 068 // The rule ID for this DIT structure rule. 069 private final int ruleID; 070 071 // The name form for this DIT structure rule. 072 private final NameForm nameForm; 073 074 // The set of additional name-value pairs associated with this DIT 075 // structure rule. 076 private final Map<String,List<String>> extraProperties; 077 078 // The set of names for this DIT structure rule, in a mapping 079 // between the all-lowercase form and the user-defined form. 080 private final Map<String,String> names; 081 082 // The set of superior DIT structure rules. 083 private final Set<DITStructureRule> superiorRules; 084 085 // The definition string for this DIT structure rule. 086 private final String definition; 087 088 // The description for this DIT structure rule. 089 private final String description; 090 091 092 093 /** 094 * Creates a new DIT structure rule with the provided information. 095 * 096 * @param definition The definition string used to create 097 * this DIT structure rule. It must not be 098 * {@code null}. 099 * @param names The set of names for this DIT structure 100 * rule, mapping the lowercase names to the 101 * user-defined values. 102 * @param ruleID The rule ID for this DIT structure rule. 103 * @param description The description for this DIT structure 104 * rule. 105 * @param isObsolete Indicates whether this DIT structure 106 * rule is declared "obsolete". 107 * @param nameForm The name form for this DIT structure 108 * rule. 109 * @param superiorRules References to the superior rules for 110 * this DIT structure rule. 111 * @param extraProperties The set of "extra" properties associated 112 * with this DIT structure rules. 113 */ 114 public DITStructureRule(String definition, Map<String,String> names, 115 int ruleID, String description, 116 boolean isObsolete, NameForm nameForm, 117 Set<DITStructureRule> superiorRules, 118 Map<String,List<String>> extraProperties) 119 { 120 ensureNotNull(definition); 121 122 this.ruleID = ruleID; 123 this.description = description; 124 this.isObsolete = isObsolete; 125 this.nameForm = nameForm; 126 127 int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME); 128 if (schemaFilePos > 0) 129 { 130 String defStr; 131 try 132 { 133 int firstQuotePos = definition.indexOf('\'', schemaFilePos); 134 int secondQuotePos = definition.indexOf('\'', 135 firstQuotePos+1); 136 137 defStr = definition.substring(0, schemaFilePos).trim() + " " + 138 definition.substring(secondQuotePos+1).trim(); 139 } 140 catch (Exception e) 141 { 142 if (debugEnabled()) 143 { 144 TRACER.debugCaught(DebugLogLevel.ERROR, e); 145 } 146 147 defStr = definition; 148 } 149 150 this.definition = defStr; 151 } 152 else 153 { 154 this.definition = definition; 155 } 156 157 if ((names == null) || names.isEmpty()) 158 { 159 this.names = new LinkedHashMap<String,String>(0); 160 } 161 else 162 { 163 this.names = new LinkedHashMap<String,String>(names); 164 } 165 166 if ((superiorRules == null) || superiorRules.isEmpty()) 167 { 168 this.superiorRules = new LinkedHashSet<DITStructureRule>(0); 169 } 170 else 171 { 172 this.superiorRules = 173 new LinkedHashSet<DITStructureRule>(superiorRules); 174 } 175 176 if ((extraProperties == null) || extraProperties.isEmpty()) 177 { 178 this.extraProperties = 179 new LinkedHashMap<String,List<String>>(0); 180 } 181 else 182 { 183 this.extraProperties = 184 new LinkedHashMap<String,List<String>>(extraProperties); 185 } 186 } 187 188 189 190 /** 191 * Retrieves the definition string used to create this DIT structure 192 * rule. 193 * 194 * @return The definition string used to create this DIT structure 195 * rule. 196 */ 197 public String getDefinition() 198 { 199 return definition; 200 } 201 202 203 204 /** 205 * Creates a new instance of this DIT structure rule based on the 206 * definition string. It will also preserve other state information 207 * associated with this DIT structure rule that is not included in 208 * the definition string (e.g., the name of the schema file with 209 * which it is associated). 210 * 211 * @return The new instance of this DIT structure rule based on the 212 * definition string. 213 * 214 * @throws DirectoryException If a problem occurs while attempting 215 * to create a new DIT structure rule 216 * instance from the definition string. 217 */ 218 public DITStructureRule recreateFromDefinition() 219 throws DirectoryException 220 { 221 ByteString value = ByteStringFactory.create(definition); 222 Schema schema = DirectoryConfig.getSchema(); 223 224 DITStructureRule dsr = 225 DITStructureRuleSyntax.decodeDITStructureRule(value, schema, 226 false); 227 dsr.setSchemaFile(getSchemaFile()); 228 229 return dsr; 230 } 231 232 233 234 /** 235 * Retrieves the set of names that may be used to reference this DIT 236 * structure rule. The returned mapping will be between an all 237 * lower-case form of the name and a name in the user-defined form 238 * (which may include mixed capitalization). 239 * 240 * @return The set of names that may be used to reference this DIT 241 * structure rule. 242 */ 243 public Map<String,String> getNames() 244 { 245 return names; 246 } 247 248 249 250 /** 251 * Indicates whether this DIT structure rule has the specified name. 252 * 253 * @param lowerName The lowercase name for which to make the 254 * determination. 255 * 256 * @return {@code true} if the specified name is assigned to this 257 * DIT structure rule, or {@code false} if not. 258 */ 259 public boolean hasName(String lowerName) 260 { 261 return names.containsKey(lowerName); 262 } 263 264 265 266 /** 267 * Retrieves the rule ID for this DIT structure rule. 268 * 269 * @return The rule ID for this DIT structure rule. 270 */ 271 public int getRuleID() 272 { 273 return ruleID; 274 } 275 276 277 278 /** 279 * Retrieves the name or rule ID for this DIT structure rule. If it 280 * has one or more names, then the primary name will be returned. 281 * If it does not have any names, then the rule ID will be returned. 282 * 283 * @return The name or rule ID for this DIT structure rule. 284 */ 285 public String getNameOrRuleID() 286 { 287 if (names.isEmpty()) 288 { 289 return String.valueOf(ruleID); 290 } 291 else 292 { 293 return names.values().iterator().next(); 294 } 295 } 296 297 298 299 /** 300 * Retrieves the path to the schema file that contains the 301 * definition for this DIT structure rule. 302 * 303 * @return The path to the schema file that contains the definition 304 * for this DIT structure rule, or {@code null} if it 305 * is not known or if it is not stored in any schema file. 306 */ 307 public String getSchemaFile() 308 { 309 List<String> values = 310 extraProperties.get(SCHEMA_PROPERTY_FILENAME); 311 if ((values == null) || values.isEmpty()) 312 { 313 return null; 314 } 315 316 return values.get(0); 317 } 318 319 320 321 /** 322 * Specifies the path to the schema file that contains the 323 * definition for this DIT structure rule. 324 * 325 * @param schemaFile The path to the schema file that contains the 326 * definition for this DIT structure rule. 327 */ 328 public void setSchemaFile(String schemaFile) 329 { 330 setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile); 331 } 332 333 334 335 /** 336 * Retrieves the description for this DIT structure rule. 337 * 338 * @return The description for this DIT structure rule. 339 */ 340 public String getDescription() 341 { 342 return description; 343 } 344 345 346 347 /** 348 * Retrieves the name form for this DIT structure rule. 349 * 350 * @return The name form for this DIT structure rule. 351 */ 352 public NameForm getNameForm() 353 { 354 return nameForm; 355 } 356 357 358 359 /** 360 * Retrieves the structural objectclass for the name form with which 361 * this DIT structure rule is associated. 362 * 363 * @return The structural objectclass for the name form with which 364 * this DIT structure rule is associated. 365 */ 366 public ObjectClass getStructuralClass() 367 { 368 return nameForm.getStructuralClass(); 369 } 370 371 372 373 /** 374 * Retrieves the set of superior rules for this DIT structure rule. 375 * 376 * @return The set of superior rules for this DIT structure rule. 377 */ 378 public Set<DITStructureRule> getSuperiorRules() 379 { 380 return superiorRules; 381 } 382 383 384 385 /** 386 * Indicates whether this DIT structure rule has one or more 387 * superior rules. 388 * 389 * @return {@code true} if this DIT structure rule has one or more 390 * superior rules, or {@code false} if not. 391 */ 392 public boolean hasSuperiorRules() 393 { 394 return ((superiorRules != null) && (! superiorRules.isEmpty())); 395 } 396 397 398 399 /** 400 * Indicates whether this DIT structure rule is declared "obsolete". 401 * 402 * @return {@code true} if this DIT structure rule is declared 403 * "obsolete", or {@code false} if not. 404 */ 405 public boolean isObsolete() 406 { 407 return isObsolete; 408 } 409 410 411 412 /** 413 * Retrieves a mapping between the names of any extra non-standard 414 * properties that may be associated with this DIT structure rule 415 * and the value for that property. 416 * 417 * @return A mapping between the names of any extra non-standard 418 * properties that may be associated with this DIT 419 * structure rule and the value for that property. 420 */ 421 public Map<String,List<String>> getExtraProperties() 422 { 423 return extraProperties; 424 } 425 426 427 428 /** 429 * Retrieves the value of the specified "extra" property for this 430 * DIT structure rule. 431 * 432 * @param propertyName The name of the "extra" property for which 433 * to retrieve the value. 434 * 435 * @return The value of the specified "extra" property for this DIT 436 * structure rule, or {@code null} if no such property is 437 * defined. 438 */ 439 public List<String> getExtraProperty(String propertyName) 440 { 441 return extraProperties.get(propertyName); 442 } 443 444 445 446 /** 447 * Specifies the provided "extra" property for this DIT structure 448 * rule. 449 * 450 * @param name The name for the "extra" property. It must not be 451 * {@code null}. 452 * @param value The value for the "extra" property, or 453 * {@code null} if the property is to be removed. 454 */ 455 public void setExtraProperty(String name, String value) 456 { 457 ensureNotNull(name); 458 459 if (value == null) 460 { 461 extraProperties.remove(name); 462 } 463 else 464 { 465 LinkedList<String> values = new LinkedList<String>(); 466 values.add(value); 467 468 extraProperties.put(name, values); 469 } 470 } 471 472 473 474 /** 475 * Specifies the provided "extra" property for this DIT structure 476 * rule. 477 * 478 * @param name The name for the "extra" property. It must not 479 * be {@code null}. 480 * @param values The set of value for the "extra" property, or 481 * {@code null} if the property is to be removed. 482 */ 483 public void setExtraProperty(String name, List<String> values) 484 { 485 ensureNotNull(name); 486 487 if ((values == null) || values.isEmpty()) 488 { 489 extraProperties.remove(name); 490 } 491 else 492 { 493 LinkedList<String> valuesCopy = new LinkedList<String>(values); 494 extraProperties.put(name, valuesCopy); 495 } 496 } 497 498 499 500 /** 501 * Indicates whether the provided object is equal to this DIT 502 * structure rule. The object will be considered equal if it is a 503 * DIT structure rule with the same OID as the current type. 504 * 505 * @param o The object for which to make the determination. 506 * 507 * @return {@code true} if the provided object is equal to this 508 * attribute, or {@code false} if not. 509 */ 510 public boolean equals(Object o) 511 { 512 if (this == o) 513 { 514 return true; 515 } 516 517 if ((o == null) || (! (o instanceof DITStructureRule))) 518 { 519 return false; 520 } 521 522 return (ruleID == ((DITStructureRule) o).ruleID); 523 } 524 525 526 527 /** 528 * Retrieves the hash code for this DIT structure rule. It will be 529 * equal to the rule ID. 530 * 531 * @return The hash code for this DIT structure rule. 532 */ 533 public int hashCode() 534 { 535 return ruleID; 536 } 537 538 539 540 /** 541 * Retrieves the string representation of this attribute type in the 542 * form specified in RFC 2252. 543 * 544 * @return The string representation of this attribute type in the 545 * form specified in RFC 2252. 546 */ 547 public String toString() 548 { 549 StringBuilder buffer = new StringBuilder(); 550 toString(buffer, true); 551 return buffer.toString(); 552 } 553 554 555 556 /** 557 * Appends a string representation of this attribute type in the 558 * form specified in RFC 2252 to the provided buffer. 559 * 560 * @param buffer The buffer to which the information 561 * should be appended. 562 * @param includeFileElement Indicates whether to include an 563 * "extra" property that specifies the 564 * path to the schema file from which 565 * this DIT structure rule was loaded. 566 */ 567 public void toString(StringBuilder buffer, 568 boolean includeFileElement) 569 { 570 buffer.append("( "); 571 buffer.append(ruleID); 572 573 if (! names.isEmpty()) 574 { 575 Iterator<String> iterator = names.values().iterator(); 576 577 String firstName = iterator.next(); 578 if (iterator.hasNext()) 579 { 580 buffer.append(" NAME ( '"); 581 buffer.append(firstName); 582 583 while (iterator.hasNext()) 584 { 585 buffer.append("' '"); 586 buffer.append(iterator.next()); 587 } 588 589 buffer.append("' )"); 590 } 591 else 592 { 593 buffer.append(" NAME '"); 594 buffer.append(firstName); 595 buffer.append("'"); 596 } 597 } 598 599 if ((description != null) && (description.length() > 0)) 600 { 601 buffer.append(" DESC '"); 602 buffer.append(description); 603 buffer.append("'"); 604 } 605 606 if (isObsolete) 607 { 608 buffer.append(" OBSOLETE"); 609 } 610 611 buffer.append(" FORM "); 612 buffer.append(nameForm.getNameOrOID()); 613 614 if ((superiorRules != null) && (! superiorRules.isEmpty())) 615 { 616 Iterator<DITStructureRule> iterator = superiorRules.iterator(); 617 618 int firstRule = iterator.next().getRuleID(); 619 if (iterator.hasNext()) 620 { 621 buffer.append(" SUP ( "); 622 buffer.append(firstRule); 623 624 while (iterator.hasNext()) 625 { 626 buffer.append(" "); 627 buffer.append(iterator.next().getRuleID()); 628 } 629 630 buffer.append(" )"); 631 } 632 else 633 { 634 buffer.append(" SUP "); 635 buffer.append(firstRule); 636 } 637 } 638 639 if (! extraProperties.isEmpty()) 640 { 641 for (String property : extraProperties.keySet()) 642 { 643 if ((! includeFileElement) && 644 property.equals(SCHEMA_PROPERTY_FILENAME)) 645 { 646 continue; 647 } 648 649 List<String> valueList = extraProperties.get(property); 650 651 buffer.append(" "); 652 buffer.append(property); 653 654 if (valueList.size() == 1) 655 { 656 buffer.append(" '"); 657 buffer.append(valueList.get(0)); 658 buffer.append("'"); 659 } 660 else 661 { 662 buffer.append(" ( "); 663 664 for (String value : valueList) 665 { 666 buffer.append("'"); 667 buffer.append(value); 668 buffer.append("' "); 669 } 670 671 buffer.append(")"); 672 } 673 } 674 } 675 676 buffer.append(" )"); 677 } 678 } 679