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.EnumSet; 035 036 037 038 /** 039 * Duration property definition. 040 * <p> 041 * A duration property definition comprises of: 042 * <ul> 043 * <li>a <i>base unit</i> - specifies the minimum granularity which 044 * can be used to specify duration property values. For example, if 045 * the base unit is in seconds then values represented in milliseconds 046 * will not be permitted. The default base unit is seconds 047 * <li>an optional <i>maximum unit</i> - specifies the biggest 048 * duration unit which can be used to specify duration property 049 * values. Values presented in units greater than this unit will not 050 * be permitted. There is no default maximum unit 051 * <li><i>lower limit</i> - specifies the smallest duration 052 * permitted by the property. The default lower limit is 0 and can 053 * never be less than 0 054 * <li>an optional <i>upper limit</i> - specifies the biggest 055 * duration permitted by the property. By default, there is no upper 056 * limit 057 * <li>support for <i>unlimited</i> durations - when permitted users 058 * can specify "unlimited" durations. These are represented using the 059 * decoded value, -1, or the encoded string value "unlimited". By 060 * default, unlimited durations are not permitted. In addition, it is 061 * not possible to define an upper limit and support unlimited values. 062 * </ul> 063 * Decoded values are represented using <code>long</code> values in 064 * the base unit defined for the duration property definition. 065 */ 066 public final class DurationPropertyDefinition extends PropertyDefinition<Long> { 067 068 // String used to represent unlimited durations. 069 private static final String UNLIMITED = "unlimited"; 070 071 // The base unit for this property definition. 072 private final DurationUnit baseUnit; 073 074 // The optional maximum unit for this property definition. 075 private final DurationUnit maximumUnit; 076 077 // The lower limit of the property value in milli-seconds. 078 private final long lowerLimit; 079 080 // The optional upper limit of the property value in milli-seconds. 081 private final Long upperLimit; 082 083 // Indicates whether this property allows the use of the "unlimited" 084 // duration value (represented using a -1L or the string 085 // "unlimited"). 086 private final boolean allowUnlimited; 087 088 089 090 /** 091 * An interface for incrementally constructing duration property 092 * definitions. 093 */ 094 public static class Builder extends 095 AbstractBuilder<Long, DurationPropertyDefinition> { 096 097 // The base unit for this property definition. 098 private DurationUnit baseUnit = DurationUnit.SECONDS; 099 100 // The optional maximum unit for this property definition. 101 private DurationUnit maximumUnit = null; 102 103 // The lower limit of the property value in milli-seconds. 104 private long lowerLimit = 0L; 105 106 // The optional upper limit of the property value in 107 // milli-seconds. 108 private Long upperLimit = null; 109 110 // Indicates whether this property allows the use of the 111 // "unlimited" duration value (represented using a -1L or the 112 // string "unlimited"). 113 private boolean allowUnlimited = false; 114 115 116 117 // Private constructor 118 private Builder(AbstractManagedObjectDefinition<?, ?> d, 119 String propertyName) { 120 super(d, propertyName); 121 } 122 123 124 125 /** 126 * Set the base unit for this property definition (values 127 * including limits are specified in this unit). By default a 128 * duration property definition uses seconds. 129 * 130 * @param unit 131 * The string representation of the base unit (must not 132 * be <code>null</code>). 133 * @throws IllegalArgumentException 134 * If the provided unit name did not correspond to a 135 * known duration unit, or if the base unit is bigger 136 * than the maximum unit. 137 */ 138 public final void setBaseUnit(String unit) throws IllegalArgumentException { 139 ensureNotNull(unit); 140 141 setBaseUnit(DurationUnit.getUnit(unit)); 142 } 143 144 145 146 /** 147 * Set the base unit for this property definition (values 148 * including limits are specified in this unit). By default a 149 * duration property definition uses seconds. 150 * 151 * @param unit 152 * The base unit (must not be <code>null</code>). 153 * @throws IllegalArgumentException 154 * If the provided base unit is bigger than the maximum 155 * unit. 156 */ 157 public final void setBaseUnit(DurationUnit unit) 158 throws IllegalArgumentException { 159 ensureNotNull(unit); 160 161 // Make sure that the base unit is not bigger than the maximum 162 // unit. 163 if (maximumUnit != null) { 164 if (unit.getDuration() > maximumUnit.getDuration()) { 165 throw new IllegalArgumentException( 166 "Base unit greater than maximum unit"); 167 } 168 } 169 170 this.baseUnit = unit; 171 } 172 173 174 175 /** 176 * Set the maximum unit for this property definition. By default 177 * there is no maximum unit. 178 * 179 * @param unit 180 * The string representation of the maximum unit, or 181 * <code>null</code> if there should not be a maximum 182 * unit. 183 * @throws IllegalArgumentException 184 * If the provided unit name did not correspond to a 185 * known duration unit, or if the maximum unit is 186 * smaller than the base unit. 187 */ 188 public final void setMaximumUnit(String unit) 189 throws IllegalArgumentException { 190 if (unit == null) { 191 setMaximumUnit((DurationUnit) null); 192 } else { 193 setMaximumUnit(DurationUnit.getUnit(unit)); 194 } 195 } 196 197 198 199 /** 200 * Set the maximum unit for this property definition. By default 201 * there is no maximum unit. 202 * 203 * @param unit 204 * The maximum unit, or <code>null</code> if there 205 * should not be a maximum unit. 206 * @throws IllegalArgumentException 207 * If the provided maximum unit is smaller than the base 208 * unit. 209 */ 210 public final void setMaximumUnit(DurationUnit unit) 211 throws IllegalArgumentException { 212 if (unit != null) { 213 // Make sure that the maximum unit is not smaller than the 214 // base unit. 215 if (unit.getDuration() < baseUnit.getDuration()) { 216 throw new IllegalArgumentException( 217 "Maximum unit smaller than base unit"); 218 } 219 } 220 221 this.maximumUnit = unit; 222 } 223 224 225 226 /** 227 * Set the lower limit in milli-seconds. 228 * 229 * @param lowerLimit 230 * The new lower limit (must be >= 0) in milli-seconds. 231 * @throws IllegalArgumentException 232 * If a negative lower limit was specified, or the lower 233 * limit is greater than the upper limit. 234 */ 235 public final void setLowerLimit(long lowerLimit) 236 throws IllegalArgumentException { 237 if (lowerLimit < 0) { 238 throw new IllegalArgumentException("Negative lower limit"); 239 } 240 241 if (upperLimit != null && lowerLimit > upperLimit) { 242 throw new IllegalArgumentException( 243 "Lower limit greater than upper limit"); 244 } 245 246 this.lowerLimit = lowerLimit; 247 } 248 249 250 251 /** 252 * Set the lower limit using a string representation of the limit. 253 * If the string does not specify a unit, the current base unit 254 * will be used. 255 * 256 * @param lowerLimit 257 * The string representation of the new lower limit. 258 * @throws IllegalArgumentException 259 * If the lower limit could not be parsed, or if a 260 * negative lower limit was specified, or the lower 261 * limit is greater than the upper limit. 262 */ 263 public final void setLowerLimit(String lowerLimit) 264 throws IllegalArgumentException { 265 setLowerLimit(DurationUnit.parseValue(lowerLimit, baseUnit)); 266 } 267 268 269 270 /** 271 * Set the upper limit in milli-seconds. 272 * 273 * @param upperLimit 274 * The new upper limit in milli-seconds, or 275 * <code>null</code> if there is no upper limit. 276 * @throws IllegalArgumentException 277 * If a negative upper limit was specified, or the lower 278 * limit is greater than the upper limit or unlimited 279 * durations are permitted. 280 */ 281 public final void setUpperLimit(Long upperLimit) 282 throws IllegalArgumentException { 283 if (upperLimit != null) { 284 if (upperLimit < 0) { 285 throw new IllegalArgumentException("Negative upper limit"); 286 } 287 288 if (lowerLimit > upperLimit) { 289 throw new IllegalArgumentException( 290 "Lower limit greater than upper limit"); 291 } 292 293 if (allowUnlimited) { 294 throw new IllegalArgumentException( 295 "Upper limit specified when unlimited durations are permitted"); 296 } 297 } 298 299 this.upperLimit = upperLimit; 300 } 301 302 303 304 /** 305 * Set the upper limit using a string representation of the limit. 306 * If the string does not specify a unit, the current base unit 307 * will be used. 308 * 309 * @param upperLimit 310 * The string representation of the new upper limit, or 311 * <code>null</code> if there is no upper limit. 312 * @throws IllegalArgumentException 313 * If the upper limit could not be parsed, or if the 314 * lower limit is greater than the upper limit. 315 */ 316 public final void setUpperLimit(String upperLimit) 317 throws IllegalArgumentException { 318 if (upperLimit == null) { 319 setUpperLimit((Long) null); 320 } else { 321 setUpperLimit(DurationUnit.parseValue(upperLimit, baseUnit)); 322 } 323 } 324 325 326 327 /** 328 * Specify whether or not this property definition will allow 329 * unlimited values (default is false). 330 * 331 * @param allowUnlimited 332 * <code>true</code> if the property will allow 333 * unlimited values, or <code>false</code> otherwise. 334 * @throws IllegalArgumentException 335 * If unlimited values are to be permitted but there is 336 * an upper limit specified. 337 */ 338 public final void setAllowUnlimited(boolean allowUnlimited) 339 throws IllegalArgumentException { 340 if (allowUnlimited && upperLimit != null) { 341 throw new IllegalArgumentException( 342 "Upper limit specified when unlimited durations are permitted"); 343 } 344 345 this.allowUnlimited = allowUnlimited; 346 } 347 348 349 350 /** 351 * {@inheritDoc} 352 */ 353 @Override 354 protected DurationPropertyDefinition buildInstance( 355 AbstractManagedObjectDefinition<?, ?> d, String propertyName, 356 EnumSet<PropertyOption> options, 357 AdministratorAction adminAction, 358 DefaultBehaviorProvider<Long> defaultBehavior) { 359 return new DurationPropertyDefinition(d, propertyName, options, 360 adminAction, defaultBehavior, baseUnit, maximumUnit, lowerLimit, 361 upperLimit, allowUnlimited); 362 } 363 } 364 365 366 367 /** 368 * Create a duration property definition builder. 369 * 370 * @param d 371 * The managed object definition associated with this 372 * property definition. 373 * @param propertyName 374 * The property name. 375 * @return Returns the new integer property definition builder. 376 */ 377 public static Builder createBuilder(AbstractManagedObjectDefinition<?, ?> d, 378 String propertyName) { 379 return new Builder(d, propertyName); 380 } 381 382 383 384 // Private constructor. 385 private DurationPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d, 386 String propertyName, EnumSet<PropertyOption> options, 387 AdministratorAction adminAction, 388 DefaultBehaviorProvider<Long> defaultBehavior, DurationUnit baseUnit, 389 DurationUnit maximumUnit, Long lowerLimit, Long upperLimit, 390 boolean allowUnlimited) { 391 super(d, Long.class, propertyName, options, adminAction, defaultBehavior); 392 this.baseUnit = baseUnit; 393 this.maximumUnit = maximumUnit; 394 this.lowerLimit = lowerLimit; 395 this.upperLimit = upperLimit; 396 this.allowUnlimited = allowUnlimited; 397 } 398 399 400 401 /** 402 * Get the base unit for this property definition (values including 403 * limits are specified in this unit). 404 * 405 * @return Returns the base unit for this property definition 406 * (values including limits are specified in this unit). 407 */ 408 public DurationUnit getBaseUnit() { 409 return baseUnit; 410 } 411 412 413 414 /** 415 * Get the maximum unit for this property definition if specified. 416 * 417 * @return Returns the maximum unit for this property definition, or 418 * <code>null</code> if there is no maximum unit. 419 */ 420 public DurationUnit getMaximumUnit() { 421 return maximumUnit; 422 } 423 424 425 426 /** 427 * Get the lower limit in milli-seconds. 428 * 429 * @return Returns the lower limit in milli-seconds. 430 */ 431 public long getLowerLimit() { 432 return lowerLimit; 433 } 434 435 436 437 /** 438 * Get the upper limit in milli-seconds. 439 * 440 * @return Returns the upper limit in milli-seconds, or 441 * <code>null</code> if there is no upper limit. 442 */ 443 public Long getUpperLimit() { 444 return upperLimit; 445 } 446 447 448 449 /** 450 * Determine whether this property allows unlimited durations. 451 * 452 * @return Returns <code>true</code> if this this property allows 453 * unlimited durations. 454 */ 455 public boolean isAllowUnlimited() { 456 return allowUnlimited; 457 } 458 459 460 461 /** 462 * {@inheritDoc} 463 */ 464 @Override 465 public void validateValue(Long value) throws IllegalPropertyValueException { 466 ensureNotNull(value); 467 468 long nvalue = baseUnit.toMilliSeconds(value); 469 if (!allowUnlimited && nvalue < lowerLimit) { 470 throw new IllegalPropertyValueException(this, value); 471 472 // unlimited allowed 473 } else if (nvalue >= 0 && nvalue < lowerLimit) { 474 throw new IllegalPropertyValueException(this, value); 475 } 476 477 if ((upperLimit != null) && (nvalue > upperLimit)) { 478 throw new IllegalPropertyValueException(this, value); 479 } 480 } 481 482 483 484 /** 485 * {@inheritDoc} 486 */ 487 @Override 488 public String encodeValue(Long value) throws IllegalPropertyValueException { 489 ensureNotNull(value); 490 491 // Make sure that we correctly encode negative values as 492 // "unlimited". 493 if (allowUnlimited) { 494 if (value < 0) { 495 return UNLIMITED; 496 } 497 } 498 499 // Encode the size value using the base unit. 500 StringBuilder builder = new StringBuilder(); 501 builder.append(value); 502 builder.append(' '); 503 builder.append(baseUnit.toString()); 504 return builder.toString(); 505 } 506 507 508 509 /** 510 * {@inheritDoc} 511 */ 512 @Override 513 public Long decodeValue(String value) 514 throws IllegalPropertyValueStringException { 515 ensureNotNull(value); 516 517 // First check for the special "unlimited" value when necessary. 518 if (allowUnlimited) { 519 if (value.trim().equalsIgnoreCase(UNLIMITED)) { 520 return -1L; 521 } 522 } 523 524 // Parse the string representation. 525 long ms; 526 try { 527 ms = DurationUnit.parseValue(value); 528 } catch (NumberFormatException e) { 529 throw new IllegalPropertyValueStringException(this, value); 530 } 531 532 // Check the unit is in range - values must not be more granular 533 // than the base unit. 534 if ((ms % baseUnit.getDuration()) != 0) { 535 throw new IllegalPropertyValueStringException(this, value); 536 } 537 538 // Convert the value a long in the property's required unit. 539 Long i = (long) baseUnit.fromMilliSeconds(ms); 540 try { 541 validateValue(i); 542 } catch (IllegalPropertyValueException e) { 543 throw new IllegalPropertyValueStringException(this, value); 544 } 545 return i; 546 } 547 548 549 550 /** 551 * {@inheritDoc} 552 */ 553 @Override 554 public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) { 555 return v.visitDuration(this, p); 556 } 557 558 559 560 /** 561 * {@inheritDoc} 562 */ 563 @Override 564 public <R, P> R accept(PropertyValueVisitor<R, P> v, Long value, P p) { 565 return v.visitDuration(this, value, p); 566 } 567 568 569 570 /** 571 * {@inheritDoc} 572 */ 573 @Override 574 public void toString(StringBuilder builder) { 575 super.toString(builder); 576 577 builder.append(" baseUnit="); 578 builder.append(baseUnit); 579 580 if (maximumUnit != null) { 581 builder.append(" maximumUnit="); 582 builder.append(maximumUnit); 583 } 584 585 builder.append(" lowerLimit="); 586 builder.append(lowerLimit); 587 builder.append("ms"); 588 589 if (upperLimit != null) { 590 builder.append(" upperLimit="); 591 builder.append(upperLimit); 592 builder.append("ms"); 593 } 594 595 builder.append(" allowUnlimited="); 596 builder.append(allowUnlimited); 597 } 598 599 600 601 /** 602 * {@inheritDoc} 603 */ 604 @Override 605 public int compare(Long o1, Long o2) { 606 return o1.compareTo(o2); 607 } 608 609 }