001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.plugin;
021    
022    import org.crsh.util.Utils;
023    
024    import java.util.List;
025    import java.util.Arrays;
026    import java.util.Collections;
027    import java.util.HashMap;
028    import java.util.Map;
029    import java.util.concurrent.TimeUnit;
030    
031    public abstract class PropertyDescriptor<T> {
032    
033      /** The display value returned when a property is secret. */
034      public static final String SECRET_DISPLAY_VALUE = "*****";
035    
036      public static PropertyDescriptor<String> create(String name, String defaultValue, String description, boolean secret) {
037        return new PropertyDescriptor<String>(String.class, name, defaultValue, description, secret) {
038          @Override
039          protected String doParse(String s) throws Exception {
040            return s;
041          }
042        };
043      }
044    
045    
046      public static PropertyDescriptor<String> create(String name, String defaultValue, String description) {
047        return create(name, defaultValue, description, false);
048      }
049    
050      public static PropertyDescriptor<Integer> create(String name, Integer defaultValue, String description, boolean secret) {
051        return new PropertyDescriptor<Integer>(Integer.class, name, defaultValue, description, secret) {
052          @Override
053          protected Integer doParse(String s) throws Exception {
054            return Integer.parseInt(s);
055          }
056        };
057      }
058    
059      public static PropertyDescriptor<Integer> create(String name, Integer defaultValue, String description) {
060        return create(name, defaultValue, description, false);
061      }
062    
063      public static PropertyDescriptor<List> create(String name, List defaultValue, String description, boolean secret) {
064        return new PropertyDescriptor<List>(List.class, name, defaultValue, description, secret) {
065          @Override
066          protected List doParse(String s) throws Exception {
067            String[] split = Utils.split(s, ',');
068            List<String> list = Arrays.asList(split);
069            for (int i = 0;i < list.size();i++) {
070              list.set(i, list.get(i).trim());
071            }
072            return list;
073          }
074        };
075      }
076    
077      public static PropertyDescriptor<List> create(String name, List defaultValue, String description) {
078        return create(name, defaultValue, description, false);
079      }
080    
081      /** . */
082      private static final Map<String, PropertyDescriptor<?>> INTERNAL_ALL = new HashMap<String, PropertyDescriptor<?>>();
083    
084      /** . */
085      public static final Map<String, PropertyDescriptor<?>> ALL = Collections.unmodifiableMap(INTERNAL_ALL);
086    
087      /** . */
088      public static final PropertyDescriptor<TimeUnit> VFS_REFRESH_UNIT = new PropertyDescriptor<TimeUnit>(TimeUnit.class, "vfs.refresh_unit", TimeUnit.SECONDS, "The refresh time unit") {
089        @Override
090        public TimeUnit doParse(String s) {
091          return TimeUnit.valueOf(s);
092        }
093      };
094    
095      /** . */
096      public static final PropertyDescriptor<Integer> VFS_REFRESH_PERIOD = PropertyDescriptor.create("vfs.refresh_period", (Integer)null, "The refresh rate period");
097    
098      /** . */
099      public final Class<T> type;
100    
101      /** . */
102      public final String name;
103    
104      /** . */
105      public final T defaultValue;
106    
107      /** . */
108      public final String description;
109    
110      /** . */
111      public final boolean secret;
112    
113      /**
114       * Create a new property descriptor.
115       *
116       * @param type         the property type
117       * @param name         the property name
118       * @param defaultValue the default value
119       * @param description  the description
120       * @throws NullPointerException if the type, name or description is null
121       */
122      protected PropertyDescriptor(Class<T> type, String name, T defaultValue, String description) throws NullPointerException {
123        this(type, name, defaultValue, description, false);
124      }
125    
126      /**
127       * Create a new property descriptor.
128       *
129       * @param type         the property type
130       * @param name         the property name
131       * @param defaultValue the default value
132       * @param description  the description
133       * @param secret       the value is secret (like a password)
134       * @throws NullPointerException if the type, name or description is null
135       */
136      protected PropertyDescriptor(Class<T> type, String name, T defaultValue, String description, boolean secret) throws NullPointerException {
137        if (type == null) {
138          throw new NullPointerException("No null type accepted");
139        }
140        if (name == null) {
141          throw new NullPointerException("No null name accepted");
142        }
143        if (description == null) {
144          throw new NullPointerException("No null description accepted");
145        }
146    
147        this.type = type;
148        this.name = name;
149        this.defaultValue = defaultValue;
150        this.description = description;
151        this.secret = secret;
152    
153        //
154        INTERNAL_ALL.put(name, this);
155      }
156    
157      public final String getName() {
158        return name;
159      }
160    
161      public final String getDescription() {
162        return description;
163      }
164    
165      public final Class<T> getType() {
166        return type;
167      }
168    
169      public final T getDefaultValue() {
170        return defaultValue;
171      }
172    
173      public final String getDefaultDisplayValue() {
174        return secret ? SECRET_DISPLAY_VALUE : String.valueOf(defaultValue);
175      }
176    
177      /**
178       * Parse a string representation of a value and returns the corresponding typed value.
179       *
180       * @param s the string to parse
181       * @return the corresponding value
182       * @throws NullPointerException     if the argument is null
183       * @throws IllegalArgumentException if the string value cannot be parsed for some reason
184       */
185      public final T parse(String s) throws NullPointerException, IllegalArgumentException {
186        if (s == null) {
187          throw new NullPointerException("Cannot parse null property values");
188        }
189        try {
190          return doParse(s);
191        }
192        catch (Exception e) {
193          throw new IllegalArgumentException("Illegal property value " + s, e);
194        }
195      }
196    
197      @Override
198      public boolean equals(Object obj) {
199        if (obj == this) {
200          return true;
201        } else if (obj instanceof PropertyDescriptor<?>) {
202          PropertyDescriptor<?> that = (PropertyDescriptor<?>)obj;
203          return name.equals(that.name) && type.equals(that.type);
204        } else {
205          return false;
206        }
207      }
208    
209      /**
210       * Parse a string representation of a value and returns the correspondig property value.
211       *
212       * @param s the string to parse
213       * @return the corresponding property
214       * @throws NullPointerException     if the argument is null
215       * @throws IllegalArgumentException if the string value cannot be parsed for some reason
216       */
217      public final Property<T> toProperty(String s) throws NullPointerException, IllegalArgumentException {
218        T value = parse(s);
219        return new Property<T>(this, value);
220      }
221    
222      /**
223       * Implements the real parsing, the string argument must nto be null. The returned value must not be null instead an
224       * exception must be thrown.
225       *
226       * @param s the string to parse
227       * @return the related value
228       * @throws Exception any exception that would prevent parsing to hapen
229       */
230      protected abstract T doParse(String s) throws Exception;
231    
232      @Override
233      public final String toString() {
234        return "PropertyDescriptor[name=" + name + ",type=" + type.getName() + ",description=" + description + "]";
235      }
236    }