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