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.ensureNotNull; 033 034 import java.util.EnumSet; 035 036 037 038 /** 039 * Memory size property definition. 040 * <p> 041 * All memory size property values are represented in bytes using longs. 042 * <p> 043 * All values must be zero or positive and within the lower/upper limit 044 * constraints. Support is provided for "unlimited" memory sizes. These are 045 * represented using a negative memory size value or using the string 046 * "unlimited". 047 */ 048 public final class SizePropertyDefinition extends PropertyDefinition<Long> { 049 050 // String used to represent unlimited memory sizes. 051 private static final String UNLIMITED = "unlimited"; 052 053 // The lower limit of the property value in bytes. 054 private final long lowerLimit; 055 056 // The optional upper limit of the property value in bytes. 057 private final Long upperLimit; 058 059 // Indicates whether this property allows the use of the "unlimited" memory 060 // size value (represented using a -1L or the string "unlimited"). 061 private final boolean allowUnlimited; 062 063 064 065 /** 066 * An interface for incrementally constructing memory size property 067 * definitions. 068 */ 069 public static class Builder extends 070 AbstractBuilder<Long, SizePropertyDefinition> { 071 072 // The lower limit of the property value in bytes. 073 private long lowerLimit = 0L; 074 075 // The optional upper limit of the property value in bytes. 076 private Long upperLimit = null; 077 078 // Indicates whether this property allows the use of the "unlimited" memory 079 // size value (represented using a -1L or the string "unlimited"). 080 private boolean allowUnlimited = false; 081 082 083 084 // Private constructor 085 private Builder( 086 AbstractManagedObjectDefinition<?, ?> d, String propertyName) { 087 super(d, propertyName); 088 } 089 090 091 092 /** 093 * Set the lower limit in bytes. 094 * 095 * @param lowerLimit 096 * The new lower limit (must be >= 0) in bytes. 097 * @throws IllegalArgumentException 098 * If a negative lower limit was specified, or if the lower limit 099 * is greater than the upper limit. 100 */ 101 public final void setLowerLimit(long lowerLimit) 102 throws IllegalArgumentException { 103 if (lowerLimit < 0) { 104 throw new IllegalArgumentException("Negative lower limit"); 105 } 106 if (upperLimit != null && lowerLimit > upperLimit) { 107 throw new IllegalArgumentException( 108 "Lower limit greater than upper limit"); 109 } 110 this.lowerLimit = lowerLimit; 111 } 112 113 114 115 /** 116 * Set the lower limit using a string representation of the limit. 117 * 118 * @param lowerLimit 119 * The string representation of the new lower limit. 120 * @throws IllegalArgumentException 121 * If the lower limit could not be parsed, or if a negative lower 122 * limit was specified, or the lower limit is greater than the 123 * upper limit. 124 */ 125 public final void setLowerLimit(String lowerLimit) 126 throws IllegalArgumentException { 127 setLowerLimit(SizeUnit.parseValue(lowerLimit, SizeUnit.BYTES)); 128 } 129 130 131 132 /** 133 * Set the upper limit in bytes. 134 * 135 * @param upperLimit 136 * The new upper limit in bytes or <code>null</code> if there is 137 * no upper limit. 138 * @throws IllegalArgumentException 139 * If the lower limit is greater than the upper limit. 140 */ 141 public final void setUpperLimit(Long upperLimit) 142 throws IllegalArgumentException { 143 if (upperLimit != null) { 144 if (upperLimit < 0) { 145 throw new IllegalArgumentException("Negative upper limit"); 146 } 147 if (lowerLimit > upperLimit) { 148 throw new IllegalArgumentException( 149 "Lower limit greater than upper limit"); 150 } 151 } 152 this.upperLimit = upperLimit; 153 } 154 155 156 157 /** 158 * Set the upper limit using a string representation of the limit. 159 * 160 * @param upperLimit 161 * The string representation of the new upper limit, or 162 * <code>null</code> if there is no upper limit. 163 * @throws IllegalArgumentException 164 * If the upper limit could not be parsed, or if the lower limit 165 * is greater than the upper limit. 166 */ 167 public final void setUpperLimit(String upperLimit) 168 throws IllegalArgumentException { 169 if (upperLimit == null) { 170 setUpperLimit((Long) null); 171 } else { 172 setUpperLimit(SizeUnit.parseValue(upperLimit, SizeUnit.BYTES)); 173 } 174 } 175 176 177 178 /** 179 * Specify whether or not this property definition will allow unlimited 180 * values (default is false). 181 * 182 * @param allowUnlimited 183 * <code>true</code> if the property will allow unlimited values, 184 * or <code>false</code> otherwise. 185 */ 186 public final void setAllowUnlimited(boolean allowUnlimited) { 187 this.allowUnlimited = allowUnlimited; 188 } 189 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 @Override 196 protected SizePropertyDefinition buildInstance( 197 AbstractManagedObjectDefinition<?, ?> d, String propertyName, 198 EnumSet<PropertyOption> options, 199 AdministratorAction adminAction, 200 DefaultBehaviorProvider<Long> defaultBehavior) { 201 return new SizePropertyDefinition(d, propertyName, options, adminAction, 202 defaultBehavior, lowerLimit, upperLimit, allowUnlimited); 203 } 204 205 } 206 207 208 209 /** 210 * Create an memory size property definition builder. 211 * 212 * @param d 213 * The managed object definition associated with this 214 * property definition. 215 * @param propertyName 216 * The property name. 217 * @return Returns the new integer property definition builder. 218 */ 219 public static Builder createBuilder( 220 AbstractManagedObjectDefinition<?, ?> d, String propertyName) { 221 return new Builder(d, propertyName); 222 } 223 224 225 226 // Private constructor. 227 private SizePropertyDefinition( 228 AbstractManagedObjectDefinition<?, ?> d, String propertyName, 229 EnumSet<PropertyOption> options, 230 AdministratorAction adminAction, 231 DefaultBehaviorProvider<Long> defaultBehavior, Long lowerLimit, 232 Long upperLimit, boolean allowUnlimited) { 233 super(d, Long.class, propertyName, options, adminAction, 234 defaultBehavior); 235 this.lowerLimit = lowerLimit; 236 this.upperLimit = upperLimit; 237 this.allowUnlimited = allowUnlimited; 238 } 239 240 241 242 /** 243 * Get the lower limit in bytes. 244 * 245 * @return Returns the lower limit in bytes. 246 */ 247 public long getLowerLimit() { 248 return lowerLimit; 249 } 250 251 252 253 /** 254 * Get the upper limit in bytes. 255 * 256 * @return Returns the upper limit in bytes or <code>null</code> if there is 257 * no upper limit. 258 */ 259 public Long getUpperLimit() { 260 return upperLimit; 261 } 262 263 264 265 /** 266 * Determine whether this property allows unlimited memory sizes. 267 * 268 * @return Returns <code>true</code> if this this property allows unlimited 269 * memory sizes. 270 */ 271 public boolean isAllowUnlimited() { 272 return allowUnlimited; 273 } 274 275 276 277 /** 278 * {@inheritDoc} 279 */ 280 @Override 281 public void validateValue(Long value) throws IllegalPropertyValueException { 282 ensureNotNull(value); 283 284 if (!allowUnlimited && value < lowerLimit) { 285 throw new IllegalPropertyValueException(this, value); 286 287 // unlimited allowed 288 } else if (value >= 0 && value < lowerLimit) { 289 throw new IllegalPropertyValueException(this, value); 290 } 291 292 if ((upperLimit != null) && (value > upperLimit)) { 293 throw new IllegalPropertyValueException(this, value); 294 } 295 } 296 297 298 299 /** 300 * {@inheritDoc} 301 */ 302 @Override 303 public String encodeValue(Long value) throws IllegalPropertyValueException { 304 ensureNotNull(value); 305 306 // Make sure that we correctly encode negative values as "unlimited". 307 if (allowUnlimited) { 308 if (value < 0) { 309 return UNLIMITED; 310 } 311 } 312 313 // Encode the size value using the best-fit unit. 314 StringBuilder builder = new StringBuilder(); 315 SizeUnit unit = SizeUnit.getBestFitUnitExact(value); 316 317 // Cast to a long to remove fractional part (which should not be there 318 // anyway as the best-fit unit should result in an exact conversion). 319 builder.append((long) unit.fromBytes(value)); 320 builder.append(' '); 321 builder.append(unit.toString()); 322 return builder.toString(); 323 } 324 325 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override 331 public Long decodeValue(String value) 332 throws IllegalPropertyValueStringException { 333 ensureNotNull(value); 334 335 // First check for the special "unlimited" value when necessary. 336 if (allowUnlimited) { 337 if (value.trim().equalsIgnoreCase(UNLIMITED)) { 338 return -1L; 339 } 340 } 341 342 // Decode the value. 343 Long i; 344 try { 345 i = SizeUnit.parseValue(value, SizeUnit.BYTES); 346 } catch (NumberFormatException e) { 347 throw new IllegalPropertyValueStringException(this, value); 348 } 349 350 try { 351 validateValue(i); 352 } catch (IllegalPropertyValueException e) { 353 throw new IllegalPropertyValueStringException(this, value); 354 } 355 return i; 356 } 357 358 359 360 /** 361 * {@inheritDoc} 362 */ 363 @Override 364 public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) { 365 return v.visitSize(this, p); 366 } 367 368 369 370 /** 371 * {@inheritDoc} 372 */ 373 @Override 374 public <R, P> R accept(PropertyValueVisitor<R, P> v, Long value, P p) { 375 return v.visitSize(this, value, p); 376 } 377 378 379 380 /** 381 * {@inheritDoc} 382 */ 383 @Override 384 public void toString(StringBuilder builder) { 385 super.toString(builder); 386 387 builder.append(" lowerLimit="); 388 builder.append(lowerLimit); 389 390 if (upperLimit != null) { 391 builder.append(" upperLimit="); 392 builder.append(upperLimit); 393 } 394 395 builder.append(" allowUnlimited="); 396 builder.append(allowUnlimited); 397 398 } 399 400 401 402 /** 403 * {@inheritDoc} 404 */ 405 @Override 406 public int compare(Long o1, Long o2) { 407 return o1.compareTo(o2); 408 } 409 410 }