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