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}