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; 038import java.util.regex.Matcher; 039import java.util.regex.Pattern; 040import java.util.regex.PatternSyntaxException; 041 042 043 044/** 045 * String property definition. 046 */ 047public final class StringPropertyDefinition extends PropertyDefinition<String> { 048 049 /** 050 * An interface for incrementally constructing string property 051 * definitions. 052 */ 053 public static class Builder extends 054 AbstractBuilder<String, StringPropertyDefinition> { 055 056 /** 057 * Flag indicating whether values of this property are 058 * case-insensitive. 059 */ 060 private boolean isCaseInsensitive = true; 061 062 /** Optional pattern which values of this property must match. */ 063 private Pattern pattern; 064 065 /** 066 * Pattern usage which provides a user-friendly summary of the 067 * pattern if present. 068 */ 069 private String patternUsage; 070 071 072 073 /** Private constructor. */ 074 private Builder(AbstractManagedObjectDefinition<?, ?> d, 075 String propertyName) { 076 super(d, propertyName); 077 } 078 079 080 081 /** 082 * Set a flag indicating whether values of this property are 083 * case-insensitive. 084 * 085 * @param value 086 * <code>true</code> if values are case-insensitive, or 087 * <code>false</code> otherwise. 088 */ 089 public final void setCaseInsensitive(boolean value) { 090 isCaseInsensitive = value; 091 } 092 093 094 095 /** 096 * Set the regular expression pattern which values of this 097 * property must match. By default there is no pattern defined. 098 * 099 * @param pattern 100 * The regular expression pattern string, or 101 * <code>null</code> if there is no pattern. 102 * @param patternUsage 103 * A user-friendly usage string representing the pattern 104 * which can be used in error messages and help (e.g. for 105 * patterns which match a host/port combination, the 106 * usage string "HOST:PORT" would be appropriate). 107 * @throws PatternSyntaxException 108 * If the provided regular expression pattern has an 109 * invalid syntax. 110 */ 111 public final void setPattern(String pattern, String patternUsage) 112 throws PatternSyntaxException { 113 if (pattern == null) { 114 this.pattern = null; 115 this.patternUsage = null; 116 } else { 117 this.pattern = Pattern.compile(pattern); 118 this.patternUsage = patternUsage; 119 } 120 } 121 122 123 124 /** {@inheritDoc} */ 125 @Override 126 protected StringPropertyDefinition buildInstance( 127 AbstractManagedObjectDefinition<?, ?> d, String propertyName, 128 EnumSet<PropertyOption> options, 129 AdministratorAction adminAction, 130 DefaultBehaviorProvider<String> defaultBehavior) { 131 return new StringPropertyDefinition(d, propertyName, options, 132 adminAction, defaultBehavior, isCaseInsensitive, pattern, 133 patternUsage); 134 } 135 136 } 137 138 139 140 /** 141 * Create a string property definition builder. 142 * 143 * @param d 144 * The managed object definition associated with this 145 * property definition. 146 * @param propertyName 147 * The property name. 148 * @return Returns the new string property definition builder. 149 */ 150 public static Builder createBuilder(AbstractManagedObjectDefinition<?, ?> d, 151 String propertyName) { 152 return new Builder(d, propertyName); 153 } 154 155 /** 156 * Flag indicating whether values of this property are 157 * case-insensitive. 158 */ 159 private final boolean isCaseInsensitive; 160 161 /** Optional pattern which values of this property must match. */ 162 private final Pattern pattern; 163 164 /** 165 * Pattern usage which provides a user-friendly summary of the 166 * pattern if present. 167 */ 168 private final String patternUsage; 169 170 171 172 /** Private constructor. */ 173 private StringPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d, 174 String propertyName, EnumSet<PropertyOption> options, 175 AdministratorAction adminAction, 176 DefaultBehaviorProvider<String> defaultBehavior, 177 boolean isCaseInsensitive, Pattern pattern, String patternUsage) { 178 super(d, String.class, propertyName, options, adminAction, 179 defaultBehavior); 180 this.isCaseInsensitive = isCaseInsensitive; 181 this.pattern = pattern; 182 this.patternUsage = patternUsage; 183 } 184 185 186 187 /** {@inheritDoc} */ 188 @Override 189 public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) { 190 return v.visitString(this, p); 191 } 192 193 194 195 /** {@inheritDoc} */ 196 @Override 197 public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) { 198 return v.visitString(this, value, p); 199 } 200 201 202 203 /** {@inheritDoc} */ 204 @Override 205 public String decodeValue(String value) 206 throws PropertyException { 207 ifNull(value); 208 209 try { 210 validateValue(value); 211 } catch (PropertyException e) { 212 throw PropertyException.illegalPropertyValueException(this, value); 213 } 214 215 return value; 216 } 217 218 219 220 /** 221 * Gets the optional regular expression pattern which values of this 222 * property must match. 223 * 224 * @return Returns the optional regular expression pattern which 225 * values of this property must match, or <code>null</code> 226 * if there is no pattern. 227 */ 228 public Pattern getPattern() { 229 return pattern; 230 } 231 232 233 234 /** 235 * Gets the pattern synopsis of this string property definition in 236 * the default locale. 237 * 238 * @return Returns the pattern synopsis of this string property 239 * definition in the default locale, or <code>null</code> 240 * if there is no pattern synopsis (which is the case when 241 * there is no pattern matching defined for this string 242 * property definition). 243 */ 244 public LocalizableMessage getPatternSynopsis() { 245 return getPatternSynopsis(Locale.getDefault()); 246 } 247 248 249 250 /** 251 * Gets the optional pattern synopsis of this string property 252 * definition in the specified locale. 253 * 254 * @param locale 255 * The locale. 256 * @return Returns the pattern synopsis of this string property 257 * definition in the specified locale, or <code>null</code> 258 * if there is no pattern synopsis (which is the case when 259 * there is no pattern matching defined for this string 260 * property definition). 261 */ 262 public LocalizableMessage getPatternSynopsis(Locale locale) { 263 ManagedObjectDefinitionI18NResource resource = 264 ManagedObjectDefinitionI18NResource.getInstance(); 265 String property = "property." + getName() 266 + ".syntax.string.pattern.synopsis"; 267 try { 268 return resource 269 .getMessage(getManagedObjectDefinition(), property, locale); 270 } catch (MissingResourceException e) { 271 return null; 272 } 273 } 274 275 276 277 /** 278 * Gets a user-friendly usage string representing the pattern which 279 * can be used in error messages and help (e.g. for patterns which 280 * match a host/port combination, the usage string "HOST:PORT" would 281 * be appropriate). 282 * 283 * @return Returns the user-friendly pattern usage string, or 284 * <code>null</code> if there is no pattern. 285 */ 286 public String getPatternUsage() { 287 return patternUsage; 288 } 289 290 291 292 /** 293 * Query whether values of this property are case-insensitive. 294 * 295 * @return Returns <code>true</code> if values are 296 * case-insensitive, or <code>false</code> otherwise. 297 */ 298 public boolean isCaseInsensitive() { 299 return isCaseInsensitive; 300 } 301 302 303 304 /** {@inheritDoc} */ 305 @Override 306 public String normalizeValue(String value) 307 throws PropertyException { 308 ifNull(value); 309 310 if (isCaseInsensitive()) { 311 return value.trim().toLowerCase(); 312 } else { 313 return value.trim(); 314 } 315 } 316 317 318 319 /** {@inheritDoc} */ 320 @Override 321 public void validateValue(String value) throws PropertyException { 322 ifNull(value); 323 324 if (pattern != null) { 325 Matcher matcher = pattern.matcher(value); 326 if (!matcher.matches()) { 327 throw PropertyException.illegalPropertyValueException(this, value); 328 } 329 } 330 } 331}