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