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