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 }