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