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