001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.utils.configuration;
020
021import java.util.*;
022import java.util.regex.*;
023
024import org.jppf.utils.*;
025
026/**
027 * Abstract implementation of the {@link JPPFProperty} interface.
028 * @param <T> the type of the value of this property.
029 * @author Laurent Cohen
030 * @since 5.2
031 */
032public abstract class AbstractJPPFProperty<T> implements JPPFProperty<T> {
033  /**
034   * Explicit serialVersionUID.
035   */
036  private static final long serialVersionUID = 1L;
037  /**
038   * Location of the localization resource bundles.
039   */
040  private String i18nBase = "org.jppf.utils.configuration.i18n.JPPFProperties";
041  /**
042   * Constant for an empty String array.
043   */
044  private  static final String[] NO_PARAM = new String[0];
045  /**
046   * The regex pattern for identifying parameters in a property name. This pattern uses explicit reluctant quantifiers, as opposed
047   * to the default greedy quantifiers, to avoid problems when multiple property references are found in a single property value.
048   */
049  private static final Pattern PARAM_PATTERN = Pattern.compile("(?:\\<){1}?(.*?)\\>+?");
050  /**
051   * The name of this property.
052   */
053  private final String name;
054  /**
055   * Other names that may be given to this property (e.g. older names from previous versions).
056   */
057  private final String[] aliases;
058  /**
059   * The default value of this property.
060   */
061  private final T defaultValue;
062  /**
063   * The possible values for this property, if any.
064   */
065  private T[] possibleValues;
066  /**
067   * The tags that apply to this property.
068   */
069  private Set<String> tags;
070  /**
071   * Names of the parmaters used in the property's name, if any.
072   */
073  private final String[] paramNames;
074  /**
075   * Whether this property is deprecated.
076   */
077  private boolean deprecated;
078
079  /**
080   * Initialize this property with the specified name and default value.
081   * @param name the name of this property.
082   * @param defaultValue the default value of this property, used when the proeprty is not defined.
083   * @param aliases other names that may be given to this property (e.g. older names from previous versions).
084   */
085  public AbstractJPPFProperty(final String name, final T defaultValue, final String...aliases) {
086    this.name = name;
087    this.defaultValue = defaultValue;
088    this.aliases = aliases;
089    this.paramNames = parseParams(name);
090  }
091
092  @Override
093  public String getName() {
094    return name;
095  }
096
097  @Override
098  public T getDefaultValue() {
099    return defaultValue;
100  }
101
102  @Override
103  public String[] getAliases() {
104    return aliases;
105  }
106
107  @Override
108  public String toString(final T value) {
109    return (value == null) ? null : value.toString();
110  }
111
112  @Override
113  public String toString() {
114    final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
115    sb.append("name=").append(name);
116    sb.append(", default=").append(defaultValue);
117    sb.append(", aliases=").append(Arrays.asList(aliases));
118    sb.append(", valueType=").append(valueType());
119    if ((possibleValues != null) && (possibleValues.length > 0)) sb.append(", possibleValues=").append(Arrays.asList(possibleValues));
120    sb.append(", description=").append(getDocumentation());
121    sb.append(']');
122    return sb.toString();
123  }
124
125  /**
126   * Get the possible values for this property, if any is defined.
127   * @return an array of the possible values.
128   */
129  public T[] getPossibleValues() {
130    return possibleValues;
131  }
132
133  /**
134   * Set the possible values for this property.
135   * @param possibleValues an array of the possible values.
136   * @return this property.
137   */
138  public JPPFProperty<T> setPossibleValues(@SuppressWarnings("unchecked") final T... possibleValues) {
139    this.possibleValues = possibleValues;
140    return this;
141  }
142
143  @Override
144  public String getDocumentation() {
145    return getDocumentation(Locale.getDefault());
146  }
147
148  @Override
149  public String getDocumentation(final Locale locale) {
150    return LocalizationUtils.getLocalized(i18nBase, name + ".doc", locale);
151  }
152
153  @Override
154  public String getShortLabel() {
155    return getShortLabel(Locale.getDefault());
156  }
157
158  @Override
159  public String getShortLabel(final Locale locale) {
160    return LocalizationUtils.getLocalized(i18nBase, name, locale);
161  }
162
163  @Override
164  public Set<String> getTags() {
165    if (tags == null) {
166      tags = new TreeSet<>();
167      final List<String> tokens = StringUtils.parseStrings(LocalizationUtils.getLocalized(i18nBase, name + ".tags"), ",", false);
168      if (tokens != null) {
169        for (String token: tokens) {
170          final String t = token.trim();
171          if (!tags.contains(t)) tags.add(t);
172        }
173      } else tags.add("");
174    }
175    return tags;
176  }
177
178  @Override
179  public String[] getParameters() {
180    return paramNames;
181  }
182
183
184  @Override
185  public String getParameterDoc(final String param) {
186    return LocalizationUtils.getLocalized(i18nBase, name + "." + param);
187  }
188
189  /**
190   * @exclude
191   */
192  @Override
193  public String resolveName(final String...params) {
194    return resolveName(name, params);
195  }
196
197  /**
198   * @exclude
199   */
200  @Override
201  public String resolveName(final String alias, final String...params) {
202    if ((paramNames.length <= 0) || (params == null) || (params.length <= 0)) return name;
203    int n = paramNames.length;
204    if (n > params.length) n = params.length;
205    String s = alias;
206    for (int i=0; i<n; i++) s = s.replace("<" + paramNames[i] + ">", params[i]);
207    return s;
208  }
209
210  /**
211   * Resolve the parameters, if any, included in the property's name.
212   * @param name the name of the property to parse.
213   * @return an array of parameter names, possibly empty.
214   */
215  private static String[] parseParams(final String name) {
216    final List<String> params = new ArrayList<>();
217    final Matcher matcher = PARAM_PATTERN.matcher(name);
218    while (matcher.find()) {
219      final String param = matcher.group(1);
220      params.add(param);
221    }
222    return params.isEmpty() ? NO_PARAM : params.toArray(new String[params.size()]);
223  }
224
225  /**
226   * @return the location of the localization resource bundles.
227   * @exclude
228   */
229  public String getI18nBase() {
230    return i18nBase;
231  }
232
233  /**
234   * Set the location of the localization resource bundles.
235   * @param i18nBase the location to set.
236   * @exclude
237   */
238  public void setI18nBase(final String i18nBase) {
239    this.i18nBase = i18nBase;
240  }
241
242  @Override
243  public boolean isDeprecated() {
244    return deprecated;
245  }
246
247  /**
248   * @exclude
249   */
250  @Override
251  public JPPFProperty<T> setDeprecated(final boolean deprecated) {
252    this.deprecated = deprecated;
253    return this;
254  }
255
256  @Override
257  public String getDeprecatedDoc() {
258    return LocalizationUtils.getLocalized(i18nBase, name + ".deprecated");
259  }
260
261  @Override
262  public String getDeprecatedDoc(final Locale locale) {
263    return LocalizationUtils.getLocalized(i18nBase, name + ".deprecated", locale);
264  }
265}