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