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