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
020package org.crsh.plugin;
021
022import org.crsh.util.Utils;
023
024import java.util.List;
025import java.util.Arrays;
026import java.util.Collections;
027import java.util.HashMap;
028import java.util.Map;
029import java.util.concurrent.TimeUnit;
030
031public 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}