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 2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.admin; 029 030 031 032 import static org.opends.server.util.Validator.*; 033 034 import java.util.Comparator; 035 import java.util.EnumSet; 036 import java.util.Locale; 037 import java.util.MissingResourceException; 038 import java.util.Set; 039 040 import org.opends.messages.Message; 041 042 043 044 /** 045 * An interface for querying generic property definition features. 046 * <p> 047 * Property definitions are analogous to ConfigAttributes in the 048 * current model and will play a similar role. Eventually these will 049 * replace them. 050 * <p> 051 * Implementations <b>must</b> take care to implement the various 052 * comparison methods. 053 * 054 * @param <T> 055 * The data-type of values of the property. 056 */ 057 public abstract class PropertyDefinition<T> implements Comparator<T>, 058 Comparable<PropertyDefinition<?>> { 059 060 /** 061 * An interface for incrementally constructing property definitions. 062 * 063 * @param <T> 064 * The data-type of values of the property. 065 * @param <D> 066 * The type of property definition constructed by this 067 * builder. 068 */ 069 protected abstract static class AbstractBuilder 070 <T, D extends PropertyDefinition<T>> { 071 072 // The administrator action. 073 private AdministratorAction adminAction; 074 075 // The default behavior provider. 076 private DefaultBehaviorProvider<T> defaultBehavior; 077 078 // The abstract managed object 079 private final AbstractManagedObjectDefinition<?, ?> definition; 080 081 // The options applicable to this definition. 082 private final EnumSet<PropertyOption> options; 083 084 // The name of this property definition. 085 private final String propertyName; 086 087 088 089 /** 090 * Create a property definition builder. 091 * 092 * @param d 093 * The managed object definition associated with this 094 * property definition. 095 * @param propertyName 096 * The property name. 097 */ 098 protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> d, 099 String propertyName) { 100 this.definition = d; 101 this.propertyName = propertyName; 102 this.options = EnumSet.noneOf(PropertyOption.class); 103 this.adminAction = new AdministratorAction(AdministratorAction.Type.NONE, 104 d, propertyName); 105 this.defaultBehavior = new UndefinedDefaultBehaviorProvider<T>(); 106 } 107 108 109 110 /** 111 * Construct a property definition based on the properties of this 112 * builder. 113 * 114 * @return The new property definition. 115 */ 116 public final D getInstance() { 117 return buildInstance(definition, propertyName, options, adminAction, 118 defaultBehavior); 119 } 120 121 122 123 /** 124 * Set the administrator action. 125 * 126 * @param adminAction 127 * The administrator action. 128 */ 129 public final void setAdministratorAction(AdministratorAction adminAction) { 130 ensureNotNull(adminAction); 131 this.adminAction = adminAction; 132 } 133 134 135 136 /** 137 * Set the default behavior provider. 138 * 139 * @param defaultBehavior 140 * The default behavior provider. 141 */ 142 public final void setDefaultBehaviorProvider( 143 DefaultBehaviorProvider<T> defaultBehavior) { 144 ensureNotNull(defaultBehavior); 145 this.defaultBehavior = defaultBehavior; 146 } 147 148 149 150 /** 151 * Add a property definition option. 152 * 153 * @param option 154 * The property option. 155 */ 156 public final void setOption(PropertyOption option) { 157 ensureNotNull(option); 158 options.add(option); 159 } 160 161 162 163 /** 164 * Build a property definition based on the properties of this 165 * builder. 166 * 167 * @param d 168 * The managed object definition associated with this 169 * property definition. 170 * @param propertyName 171 * The property name. 172 * @param options 173 * Options applicable to this definition. 174 * @param adminAction 175 * The administrator action. 176 * @param defaultBehavior 177 * The default behavior provider. 178 * @return The new property definition. 179 */ 180 protected abstract D buildInstance(AbstractManagedObjectDefinition<?, ?> d, 181 String propertyName, EnumSet<PropertyOption> options, 182 AdministratorAction adminAction, 183 DefaultBehaviorProvider<T> defaultBehavior); 184 } 185 186 // The administrator action. 187 private final AdministratorAction adminAction; 188 189 // The default behavior provider. 190 private final DefaultBehaviorProvider<T> defaultBehavior; 191 192 // The abstract managed object 193 private final AbstractManagedObjectDefinition<?, ?> definition; 194 195 // Options applicable to this definition. 196 private final Set<PropertyOption> options; 197 198 // The property name. 199 private final String propertyName; 200 201 // The property value class. 202 private final Class<T> theClass; 203 204 205 206 /** 207 * Create a property definition. 208 * 209 * @param d 210 * The managed object definition associated with this 211 * property definition. 212 * @param theClass 213 * The property value class. 214 * @param propertyName 215 * The property name. 216 * @param options 217 * Options applicable to this definition. 218 * @param adminAction 219 * The administrator action. 220 * @param defaultBehavior 221 * The default behavior provider. 222 */ 223 protected PropertyDefinition(AbstractManagedObjectDefinition<?, ?> d, 224 Class<T> theClass, String propertyName, EnumSet<PropertyOption> options, 225 AdministratorAction adminAction, 226 DefaultBehaviorProvider<T> defaultBehavior) { 227 ensureNotNull(d, theClass, propertyName); 228 ensureNotNull(options, adminAction, defaultBehavior); 229 230 this.definition = d; 231 this.theClass = theClass; 232 this.propertyName = propertyName; 233 this.options = EnumSet.copyOf(options); 234 this.adminAction = adminAction; 235 this.defaultBehavior = defaultBehavior; 236 } 237 238 239 240 /** 241 * Apply a visitor to this property definition. 242 * 243 * @param <R> 244 * The return type of the visitor's methods. 245 * @param <P> 246 * The type of the additional parameters to the visitor's 247 * methods. 248 * @param v 249 * The property definition visitor. 250 * @param p 251 * Optional additional visitor parameter. 252 * @return Returns a result as specified by the visitor. 253 */ 254 public abstract <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p); 255 256 257 258 /** 259 * Apply a visitor to a property value associated with this property 260 * definition. 261 * 262 * @param <R> 263 * The return type of the visitor's methods. 264 * @param <P> 265 * The type of the additional parameters to the visitor's 266 * methods. 267 * @param v 268 * The property value visitor. 269 * @param value 270 * The property value. 271 * @param p 272 * Optional additional visitor parameter. 273 * @return Returns a result as specified by the visitor. 274 */ 275 public abstract <R, P> R accept(PropertyValueVisitor<R, P> v, T value, P p); 276 277 278 279 /** 280 * Cast the provided value to the type associated with this property 281 * definition. 282 * <p> 283 * This method only casts the object to the required type; it does 284 * not validate the value once it has been cast. Subsequent 285 * validation should be performed using the method 286 * {@link #validateValue(Object)}. 287 * <p> 288 * This method guarantees the following expression is always 289 * <code>true</code>: 290 * 291 * <pre> 292 * PropertyDefinition d; 293 * x == d.cast(x); 294 * </pre> 295 * 296 * @param object 297 * The property value to be cast (can be <code>null</code>). 298 * @return Returns the property value cast to the correct type. 299 * @throws ClassCastException 300 * If the provided property value did not have the correct 301 * type. 302 */ 303 public final T castValue(Object object) throws ClassCastException { 304 return theClass.cast(object); 305 } 306 307 308 309 /** 310 * Compares two property values for order. Returns a negative 311 * integer, zero, or a positive integer as the first argument is 312 * less than, equal to, or greater than the second. 313 * <p> 314 * This default implementation normalizes both values using 315 * {@link #normalizeValue(Object)} and then performs a 316 * case-sensitive string comparison. 317 * 318 * @param o1 319 * the first object to be compared. 320 * @param o2 321 * the second object to be compared. 322 * @return a negative integer, zero, or a positive integer as the 323 * first argument is less than, equal to, or greater than 324 * the second. 325 */ 326 public int compare(T o1, T o2) { 327 ensureNotNull(o1, o2); 328 329 String s1 = normalizeValue(o1); 330 String s2 = normalizeValue(o2); 331 332 return s1.compareTo(s2); 333 } 334 335 336 337 /** 338 * Compares this property definition with the specified property 339 * definition for order. Returns a negative integer, zero, or a 340 * positive integer if this property definition is less than, equal 341 * to, or greater than the specified property definition. 342 * <p> 343 * The ordering must be determined first from the property name and 344 * then base on the underlying value type. 345 * 346 * @param o 347 * The reference property definition with which to compare. 348 * @return Returns a negative integer, zero, or a positive integer 349 * if this property definition is less than, equal to, or 350 * greater than the specified property definition. 351 */ 352 public final int compareTo(PropertyDefinition<?> o) { 353 int rc = propertyName.compareTo(o.propertyName); 354 if (rc == 0) { 355 rc = theClass.getName().compareTo(o.theClass.getName()); 356 } 357 return rc; 358 } 359 360 361 362 /** 363 * Parse and validate a string representation of a property value. 364 * 365 * @param value 366 * The property string value (must not be <code>null</code>). 367 * @return Returns the decoded property value. 368 * @throws IllegalPropertyValueStringException 369 * If the property value string is invalid. 370 */ 371 public abstract T decodeValue(String value) 372 throws IllegalPropertyValueStringException; 373 374 375 376 /** 377 * Encode the provided property value into its string 378 * representation. 379 * <p> 380 * This default implementation simply returns invokes the 381 * {@link Object#toString()} method on the provided value. 382 * 383 * @param value 384 * The property value (must not be <code>null</code>). 385 * @return Returns the encoded property string value. 386 * @throws IllegalPropertyValueException 387 * If the property value is invalid. 388 */ 389 public String encodeValue(T value) throws IllegalPropertyValueException { 390 ensureNotNull(value); 391 392 return value.toString(); 393 } 394 395 396 397 /** 398 * Indicates whether some other object is "equal to" this 399 * property definition. This method must obey the general contract 400 * of <tt>Object.equals(Object)</tt>. Additionally, this method 401 * can return <tt>true</tt> <i>only</i> if the specified Object 402 * is also a property definition and it has the same name, as 403 * returned by {@link #getName()}, and also is deemed to be 404 * "compatible" with this property definition. 405 * Compatibility means that the two property definitions share the 406 * same underlying value type and provide similar comparator 407 * implementations. 408 * 409 * @param o 410 * The reference object with which to compare. 411 * @return Returns <code>true</code> only if the specified object 412 * is also a property definition and it has the same name 413 * and is compatible with this property definition. 414 * @see java.lang.Object#equals(java.lang.Object) 415 * @see java.lang.Object#hashCode() 416 */ 417 @Override 418 public final boolean equals(Object o) { 419 if (this == o) { 420 return true; 421 } else if (o instanceof PropertyDefinition) { 422 PropertyDefinition<?> other = (PropertyDefinition<?>) o; 423 if (propertyName.equals(other.propertyName)) { 424 if (theClass.equals(other.theClass)) { 425 return true; 426 } 427 } 428 return false; 429 } else { 430 return false; 431 } 432 } 433 434 435 436 /** 437 * Get the administrator action associated with this property 438 * definition. The administrator action describes any action which 439 * the administrator must perform in order for changes to this 440 * property to take effect. 441 * 442 * @return Returns the administrator action associated with this 443 * property definition. 444 */ 445 public final AdministratorAction getAdministratorAction() { 446 return adminAction; 447 } 448 449 450 451 /** 452 * Get the default behavior provider associated with this property 453 * definition. 454 * 455 * @return Returns the default behavior provider associated with 456 * this property definition. 457 */ 458 public final DefaultBehaviorProvider<T> getDefaultBehaviorProvider() { 459 return defaultBehavior; 460 } 461 462 463 464 /** 465 * Gets the optional description of this property definition in the 466 * default locale. 467 * 468 * @return Returns the description of this property definition in 469 * the default locale, or <code>null</code> if there is no 470 * description. 471 */ 472 public final Message getDescription() { 473 return getDescription(Locale.getDefault()); 474 } 475 476 477 478 /** 479 * Gets the optional description of this property definition in the 480 * specified locale. 481 * 482 * @param locale 483 * The locale. 484 * @return Returns the description of this property definition in 485 * the specified locale, or <code>null</code> if there is 486 * no description. 487 */ 488 public final Message getDescription(Locale locale) { 489 ManagedObjectDefinitionI18NResource resource = 490 ManagedObjectDefinitionI18NResource.getInstance(); 491 String property = "property." + propertyName + ".description"; 492 try { 493 return resource.getMessage(definition, property, locale); 494 } catch (MissingResourceException e) { 495 return null; 496 } 497 } 498 499 500 501 /** 502 * Gets the managed object definition associated with this property 503 * definition. 504 * 505 * @return Returns the managed object definition associated with 506 * this property definition. 507 */ 508 public final AbstractManagedObjectDefinition<?, ?> 509 getManagedObjectDefinition() { 510 return definition; 511 } 512 513 514 515 /** 516 * Get the name of the property. 517 * 518 * @return Returns the name of the property. 519 */ 520 public final String getName() { 521 return propertyName; 522 } 523 524 525 526 /** 527 * Gets the synopsis of this property definition in the default 528 * locale. 529 * 530 * @return Returns the synopsis of this property definition in the 531 * default locale. 532 */ 533 public final Message getSynopsis() { 534 return getSynopsis(Locale.getDefault()); 535 } 536 537 538 539 /** 540 * Gets the synopsis of this property definition in the specified 541 * locale. 542 * 543 * @param locale 544 * The locale. 545 * @return Returns the synopsis of this property definition in the 546 * specified locale. 547 */ 548 public final Message getSynopsis(Locale locale) { 549 ManagedObjectDefinitionI18NResource resource = 550 ManagedObjectDefinitionI18NResource.getInstance(); 551 String property = "property." + propertyName + ".synopsis"; 552 return resource.getMessage(definition, property, locale); 553 } 554 555 556 557 /** 558 * Returns a hash code value for this property definition. The hash 559 * code should be derived from the property name and the type of 560 * values handled by this property definition. 561 * 562 * @return Returns the hash code value for this property definition. 563 */ 564 @Override 565 public final int hashCode() { 566 int rc = 17 + propertyName.hashCode(); 567 return 37 * rc + theClass.hashCode(); 568 } 569 570 571 572 /** 573 * Check if the specified option is set for this property 574 * definition. 575 * 576 * @param option 577 * The option to test. 578 * @return Returns <code>true</code> if the option is set, or 579 * <code>false</code> otherwise. 580 */ 581 public final boolean hasOption(PropertyOption option) { 582 return options.contains(option); 583 } 584 585 586 587 /** 588 * Get a normalized string representation of a property value. This 589 * can then be used for comparisons and for generating hash-codes. 590 * <p> 591 * This method may throw an exception if the provided value is 592 * invalid. However, applications should not assume that 593 * implementations of this method will always validate a value. This 594 * task is the responsibility of {@link #validateValue(Object)}. 595 * <p> 596 * This default implementation simply returns the string 597 * representation of the provided value. Sub-classes might want to 598 * override this method if this behavior is insufficient (for 599 * example, a string property definition might strip white-space and 600 * convert characters to lower-case). 601 * 602 * @param value 603 * The property value to be normalized. 604 * @return Returns the normalized property value. 605 * @throws IllegalPropertyValueException 606 * If the property value is invalid. 607 */ 608 public String normalizeValue(T value) throws IllegalPropertyValueException { 609 ensureNotNull(value); 610 611 return encodeValue(value); 612 } 613 614 615 616 /** 617 * Returns a string representation of this property definition. 618 * 619 * @return Returns a string representation of this property 620 * definition. 621 * @see Object#toString() 622 */ 623 @Override 624 public final String toString() { 625 StringBuilder builder = new StringBuilder(); 626 toString(builder); 627 return builder.toString(); 628 } 629 630 631 632 /** 633 * Append a string representation of the property definition to the 634 * provided string builder. 635 * <p> 636 * This simple implementation just outputs the propertyName of the 637 * property definition. Sub-classes should override this method to 638 * provide more complete string representations. 639 * 640 * @param builder 641 * The string builder where the string representation 642 * should be appended. 643 */ 644 public void toString(StringBuilder builder) { 645 builder.append(propertyName); 646 } 647 648 649 650 /** 651 * Determine if the provided property value is valid according to 652 * this property definition. 653 * 654 * @param value 655 * The property value (must not be <code>null</code>). 656 * @throws IllegalPropertyValueException 657 * If the property value is invalid. 658 */ 659 public abstract void validateValue(T value) 660 throws IllegalPropertyValueException; 661 662 663 664 /** 665 * Performs any run-time initialization required by this property 666 * definition. This may include resolving managed object paths and 667 * property names. 668 * 669 * @throws Exception 670 * If this property definition could not be initialized. 671 */ 672 protected void initialize() throws Exception { 673 // No implementation required. 674 } 675 }