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 */
027
028package org.opends.server.admin;
029import org.forgerock.i18n.LocalizableMessage;
030
031
032
033import static org.forgerock.util.Reject.ifNull;
034
035import java.util.EnumSet;
036import java.util.Locale;
037import java.util.MissingResourceException;
038
039
040
041/**
042 * Integer property definition.
043 * <p>
044 * All values must be zero or positive and within the lower/upper limit
045 * constraints. Support is provided for "unlimited" values. These are
046 * represented using a negative value or using the string "unlimited".
047 */
048public final class IntegerPropertyDefinition extends
049    PropertyDefinition<Integer> {
050
051  /** String used to represent unlimited. */
052  private static final String UNLIMITED = "unlimited";
053
054  /** The lower limit of the property value. */
055  private final int lowerLimit;
056
057  /** The optional upper limit of the property value. */
058  private final Integer upperLimit;
059
060  /**
061   * Indicates whether this property allows the use of the "unlimited" value
062   * (represented using a -1 or the string "unlimited").
063   */
064  private final boolean allowUnlimited;
065
066
067
068  /**
069   * An interface for incrementally constructing integer property definitions.
070   */
071  public static class Builder extends
072      AbstractBuilder<Integer, IntegerPropertyDefinition> {
073
074    /** The lower limit of the property value. */
075    private int lowerLimit;
076
077    /** The optional upper limit of the property value. */
078    private Integer upperLimit;
079
080    /**
081     * Indicates whether this property allows the use of the "unlimited" value
082     * (represented using a -1 or the string "unlimited").
083     */
084    private boolean allowUnlimited;
085
086
087
088    /** Private constructor. */
089    private Builder(
090        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
091      super(d, propertyName);
092    }
093
094
095
096    /**
097     * Set the lower limit.
098     *
099     * @param lowerLimit
100     *          The new lower limit (must be >= 0).
101     * @throws IllegalArgumentException
102     *           If a negative lower limit was specified or the lower limit is
103     *           greater than the upper limit.
104     */
105    public final void setLowerLimit(int lowerLimit)
106        throws IllegalArgumentException {
107      if (lowerLimit < 0) {
108        throw new IllegalArgumentException("Negative lower limit");
109      }
110      if (upperLimit != null && lowerLimit > upperLimit) {
111        throw new IllegalArgumentException(
112            "Lower limit greater than upper limit");
113      }
114      this.lowerLimit = lowerLimit;
115    }
116
117
118
119    /**
120     * Set the upper limit.
121     *
122     * @param upperLimit
123     *          The new upper limit or <code>null</code> if there is no upper
124     *          limit.
125     */
126    public final void setUpperLimit(Integer upperLimit) {
127      if (upperLimit != null) {
128        if (upperLimit < 0) {
129          throw new IllegalArgumentException("Negative lower limit");
130        }
131        if (lowerLimit > upperLimit) {
132          throw new IllegalArgumentException(
133              "Lower limit greater than upper limit");
134        }
135      }
136      this.upperLimit = upperLimit;
137    }
138
139
140
141    /**
142     * Specify whether or not this property definition will allow unlimited
143     * values (default is false).
144     *
145     * @param allowUnlimited
146     *          <code>true</code> if the property will allow unlimited values,
147     *          or <code>false</code> otherwise.
148     */
149    public final void setAllowUnlimited(boolean allowUnlimited) {
150      this.allowUnlimited = allowUnlimited;
151    }
152
153
154
155    /** {@inheritDoc} */
156    @Override
157    protected IntegerPropertyDefinition buildInstance(
158        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
159        EnumSet<PropertyOption> options,
160        AdministratorAction adminAction,
161        DefaultBehaviorProvider<Integer> defaultBehavior) {
162      return new IntegerPropertyDefinition(d, propertyName, options,
163          adminAction, defaultBehavior, lowerLimit, upperLimit, allowUnlimited);
164    }
165
166  }
167
168
169
170  /**
171   * Create an integer property definition builder.
172   *
173   * @param d
174   *          The managed object definition associated with this
175   *          property definition.
176   * @param propertyName
177   *          The property name.
178   * @return Returns the new integer property definition builder.
179   */
180  public static Builder createBuilder(
181      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
182    return new Builder(d, propertyName);
183  }
184
185
186
187  /** Private constructor. */
188  private IntegerPropertyDefinition(
189      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
190      EnumSet<PropertyOption> options,
191      AdministratorAction adminAction,
192      DefaultBehaviorProvider<Integer> defaultBehavior, int lowerLimit,
193      Integer upperLimit, boolean allowUnlimited) {
194    super(d, Integer.class, propertyName, options, adminAction,
195        defaultBehavior);
196    this.lowerLimit = lowerLimit;
197    this.upperLimit = upperLimit;
198    this.allowUnlimited = allowUnlimited;
199  }
200
201
202
203  /**
204   * Get the lower limit.
205   *
206   * @return Returns the lower limit.
207   */
208  public int getLowerLimit() {
209    return lowerLimit;
210  }
211
212
213
214  /**
215   * Get the upper limit.
216   *
217   * @return Returns the upper limit or <code>null</code> if there is no upper
218   *         limit.
219   */
220  public Integer getUpperLimit() {
221    return upperLimit;
222  }
223
224
225
226  /**
227   * Gets the optional unit synopsis of this integer property
228   * definition in the default locale.
229   *
230   * @return Returns the unit synopsis of this integer property
231   *         definition in the default locale, or <code>null</code>
232   *         if there is no unit synopsis.
233   */
234  public LocalizableMessage getUnitSynopsis() {
235    return getUnitSynopsis(Locale.getDefault());
236  }
237
238
239
240  /**
241   * Gets the optional unit synopsis of this integer property
242   * definition in the specified locale.
243   *
244   * @param locale
245   *          The locale.
246   * @return Returns the unit synopsis of this integer property
247   *         definition in the specified locale, or <code>null</code>
248   *         if there is no unit synopsis.
249   */
250  public LocalizableMessage getUnitSynopsis(Locale locale) {
251    ManagedObjectDefinitionI18NResource resource =
252      ManagedObjectDefinitionI18NResource.getInstance();
253    String property = "property." + getName() + ".syntax.integer.unit-synopsis";
254    try {
255      return resource.getMessage(getManagedObjectDefinition(),
256          property, locale);
257    } catch (MissingResourceException e) {
258      return null;
259    }
260  }
261
262
263
264  /**
265   * Determine whether this property allows unlimited values.
266   *
267   * @return Returns <code>true</code> if this this property allows unlimited
268   *         values.
269   */
270  public boolean isAllowUnlimited() {
271    return allowUnlimited;
272  }
273
274
275
276  /** {@inheritDoc} */
277  @Override
278  public void validateValue(Integer value)
279      throws PropertyException {
280    ifNull(value);
281
282    if (!allowUnlimited && value < lowerLimit) {
283      throw PropertyException.illegalPropertyValueException(this, value);
284
285    // unlimited allowed
286    } else if (value >= 0 && value < lowerLimit) {
287      throw PropertyException.illegalPropertyValueException(this, value);
288    }
289
290    if (upperLimit != null && value > upperLimit) {
291      throw PropertyException.illegalPropertyValueException(this, value);
292    }
293  }
294
295  /** {@inheritDoc} */
296  @Override
297  public String encodeValue(Integer value)
298          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    return value.toString();
307  }
308
309  /** {@inheritDoc} */
310  @Override
311  public Integer decodeValue(String value) throws PropertyException {
312    ifNull(value);
313
314    if (allowUnlimited && value.trim().equalsIgnoreCase(UNLIMITED)) {
315      return -1;
316    }
317
318    Integer i;
319    try {
320      i = Integer.valueOf(value);
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
331    return i;
332  }
333
334
335
336  /** {@inheritDoc} */
337  @Override
338  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
339    return v.visitInteger(this, p);
340  }
341
342
343
344  /** {@inheritDoc} */
345  @Override
346  public <R, P> R accept(PropertyValueVisitor<R, P> v, Integer value, P p) {
347    return v.visitInteger(this, value, p);
348  }
349
350
351
352  /** {@inheritDoc} */
353  @Override
354  public void toString(StringBuilder builder) {
355    super.toString(builder);
356
357    builder.append(" lowerLimit=");
358    builder.append(lowerLimit);
359
360    if (upperLimit != null) {
361      builder.append(" upperLimit=");
362      builder.append(upperLimit);
363    }
364
365    builder.append(" allowUnlimited=");
366    builder.append(allowUnlimited);
367  }
368
369
370
371  /** {@inheritDoc} */
372  @Override
373  public int compare(Integer o1, Integer o2) {
374    return o1.compareTo(o2);
375  }
376
377}