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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.admin;
029    import org.opends.messages.Message;
030    
031    
032    
033    import static org.opends.server.util.Validator.ensureNotNull;
034    
035    import java.util.EnumSet;
036    import java.util.Locale;
037    import java.util.MissingResourceException;
038    import java.util.regex.Matcher;
039    import java.util.regex.Pattern;
040    import java.util.regex.PatternSyntaxException;
041    
042    
043    
044    /**
045     * String property definition.
046     */
047    public 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        // Flag indicating whether values of this property are
057        // case-insensitive.
058        private boolean isCaseInsensitive = true;
059    
060        // Optional pattern which values of this property must match.
061        private Pattern pattern = null;
062    
063        // Pattern usage which provides a user-friendly summary of the
064        // pattern if present.
065        private String patternUsage = null;
066    
067    
068    
069        // Private constructor
070        private Builder(AbstractManagedObjectDefinition<?, ?> d,
071            String propertyName) {
072          super(d, propertyName);
073        }
074    
075    
076    
077        /**
078         * Set a flag indicating whether values of this property are
079         * case-insensitive.
080         *
081         * @param value
082         *          <code>true</code> if values are case-insensitive, or
083         *          <code>false</code> otherwise.
084         */
085        public final void setCaseInsensitive(boolean value) {
086          isCaseInsensitive = value;
087        }
088    
089    
090    
091        /**
092         * Set the regular expression pattern which values of this
093         * property must match. By default there is no pattern defined.
094         *
095         * @param pattern
096         *          The regular expression pattern string, or
097         *          <code>null</code> if there is no pattern.
098         * @param patternUsage
099         *          A user-friendly usage string representing the pattern
100         *          which can be used in error messages and help (e.g. for
101         *          patterns which match a host/port combination, the
102         *          usage string "HOST:PORT" would be appropriate).
103         * @throws PatternSyntaxException
104         *           If the provided regular expression pattern has an
105         *           invalid syntax.
106         */
107        public final void setPattern(String pattern, String patternUsage)
108            throws PatternSyntaxException {
109          if (pattern == null) {
110            this.pattern = null;
111            this.patternUsage = null;
112          } else {
113            this.pattern = Pattern.compile(pattern);
114            this.patternUsage = patternUsage;
115          }
116        }
117    
118    
119    
120        /**
121         * {@inheritDoc}
122         */
123        @Override
124        protected StringPropertyDefinition buildInstance(
125            AbstractManagedObjectDefinition<?, ?> d, String propertyName,
126            EnumSet<PropertyOption> options,
127            AdministratorAction adminAction,
128            DefaultBehaviorProvider<String> defaultBehavior) {
129          return new StringPropertyDefinition(d, propertyName, options,
130              adminAction, defaultBehavior, isCaseInsensitive, pattern,
131              patternUsage);
132        }
133    
134      }
135    
136    
137    
138      /**
139       * Create a string property definition builder.
140       *
141       * @param d
142       *          The managed object definition associated with this
143       *          property definition.
144       * @param propertyName
145       *          The property name.
146       * @return Returns the new string property definition builder.
147       */
148      public static Builder createBuilder(AbstractManagedObjectDefinition<?, ?> d,
149          String propertyName) {
150        return new Builder(d, propertyName);
151      }
152    
153      // Flag indicating whether values of this property are
154      // case-insensitive.
155      private final boolean isCaseInsensitive;
156    
157      // Optional pattern which values of this property must match.
158      private final Pattern pattern;
159    
160      // Pattern usage which provides a user-friendly summary of the
161      // pattern if present.
162      private final String patternUsage;
163    
164    
165    
166      // Private constructor.
167      private StringPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d,
168          String propertyName, EnumSet<PropertyOption> options,
169          AdministratorAction adminAction,
170          DefaultBehaviorProvider<String> defaultBehavior,
171          boolean isCaseInsensitive, Pattern pattern, String patternUsage) {
172        super(d, String.class, propertyName, options, adminAction,
173            defaultBehavior);
174        this.isCaseInsensitive = isCaseInsensitive;
175        this.pattern = pattern;
176        this.patternUsage = patternUsage;
177      }
178    
179    
180    
181      /**
182       * {@inheritDoc}
183       */
184      @Override
185      public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
186        return v.visitString(this, p);
187      }
188    
189    
190    
191      /**
192       * {@inheritDoc}
193       */
194      @Override
195      public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
196        return v.visitString(this, value, p);
197      }
198    
199    
200    
201      /**
202       * {@inheritDoc}
203       */
204      @Override
205      public String decodeValue(String value)
206          throws IllegalPropertyValueStringException {
207        ensureNotNull(value);
208    
209        try {
210          validateValue(value);
211        } catch (IllegalPropertyValueException e) {
212          throw new IllegalPropertyValueStringException(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 Message 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 Message 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      /**
305       * {@inheritDoc}
306       */
307      @Override
308      public String normalizeValue(String value)
309          throws IllegalPropertyValueException {
310        ensureNotNull(value);
311    
312        if (isCaseInsensitive()) {
313          return value.trim().toLowerCase();
314        } else {
315          return value.trim();
316        }
317      }
318    
319    
320    
321      /**
322       * {@inheritDoc}
323       */
324      @Override
325      public void validateValue(String value) throws IllegalPropertyValueException {
326        ensureNotNull(value);
327    
328        if (pattern != null) {
329          Matcher matcher = pattern.matcher(value);
330          if (!matcher.matches()) {
331            throw new IllegalPropertyValueException(this, value);
332          }
333        }
334      }
335    }