2 * Sone - Options.java - Copyright © 2010–2012 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sone.core;
20 import java.util.Collections;
21 import java.util.HashMap;
24 import net.pterodactylus.util.validation.Validator;
27 * Stores various options that influence Sone’s behaviour.
29 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
31 public class Options {
34 * Contains current and default value of an option.
37 * The type of the option
38 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
40 public static interface Option<T> {
43 * Returns the default value of the option.
45 * @return The default value of the option
47 public T getDefault();
50 * Returns the current value of the option. If the current value is not
51 * set (usually {@code null}), the default value is returned.
53 * @return The current value of the option
58 * Returns the real value of the option. This will also return an unset
59 * value (usually {@code null})!
61 * @return The real value of the option
66 * Validates the given value. Note that {@code null} is always a valid
70 * The value to validate
71 * @return {@code true} if this option does not have a {@link Validator}
72 * , or the {@link Validator} validates this object, {@code
75 public boolean validate(T value);
78 * Sets the current value of the option.
81 * The new value of the option
82 * @throws IllegalArgumentException
83 * if the value is not valid for this option
85 public void set(T value) throws IllegalArgumentException;
90 * Interface for objects that want to be notified when an option changes its
94 * The type of the option
95 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
97 public static interface OptionWatcher<T> {
100 * Notifies an object that an option has been changed.
103 * The option that has changed
105 * The old value of the option
107 * The new value of the option
109 public void optionChanged(Option<T> option, T oldValue, T newValue);
114 * Basic implementation of an {@link Option} that notifies an
115 * {@link OptionWatcher} if the value changes.
118 * The type of the option
119 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
121 public static class DefaultOption<T> implements Option<T> {
123 /** The default value. */
124 private final T defaultValue;
126 /** The current value. */
127 private volatile T value;
129 /** The validator. */
130 private Validator<T> validator;
132 /** The option watcher. */
133 private final OptionWatcher<T> optionWatcher;
136 * Creates a new default option.
138 * @param defaultValue
139 * The default value of the option
141 public DefaultOption(T defaultValue) {
142 this(defaultValue, (OptionWatcher<T>) null);
146 * Creates a new default option.
148 * @param defaultValue
149 * The default value of the option
151 * The validator for value validation (may be {@code null})
153 public DefaultOption(T defaultValue, Validator<T> validator) {
154 this(defaultValue, validator, null);
158 * Creates a new default option.
160 * @param defaultValue
161 * The default value of the option
162 * @param optionWatchers
163 * The option watchers (may be {@code null})
165 public DefaultOption(T defaultValue, OptionWatcher<T> optionWatchers) {
166 this(defaultValue, null, optionWatchers);
170 * Creates a new default option.
172 * @param defaultValue
173 * The default value of the option
175 * The validator for value validation (may be {@code null})
176 * @param optionWatcher
177 * The option watcher (may be {@code null})
179 public DefaultOption(T defaultValue, Validator<T> validator, OptionWatcher<T> optionWatcher) {
180 this.defaultValue = defaultValue;
181 this.validator = validator;
182 this.optionWatcher = optionWatcher;
189 public T getDefault() {
198 return (value != null) ? value : defaultValue;
202 * Returns the real value of the option. This will also return an unset
203 * value (usually {@code null})!
205 * @return The real value of the option
216 public boolean validate(T value) {
217 return (validator == null) || (value == null) || validator.validate(value);
224 public void set(T value) {
225 if ((value != null) && (validator != null) && (!validator.validate(value))) {
226 throw new IllegalArgumentException("New Value (" + value + ") could not be validated.");
228 T oldValue = this.value;
230 if (!get().equals(oldValue)) {
231 if (optionWatcher != null) {
232 optionWatcher.optionChanged(this, oldValue, get());
239 /** Holds all {@link Boolean} {@link Option}s. */
240 private final Map<String, Option<Boolean>> booleanOptions = Collections.synchronizedMap(new HashMap<String, Option<Boolean>>());
242 /** Holds all {@link Integer} {@link Option}s. */
243 private final Map<String, Option<Integer>> integerOptions = Collections.synchronizedMap(new HashMap<String, Option<Integer>>());
245 /** Holds all {@link String} {@link Option}s. */
246 private final Map<String, Option<String>> stringOptions = Collections.synchronizedMap(new HashMap<String, Option<String>>());
248 /** Holds all {@link Enum} {@link Option}s. */
249 private final Map<String, Option<? extends Enum<?>>> enumOptions = Collections.synchronizedMap(new HashMap<String, Option<? extends Enum<?>>>());
252 * Adds a boolean option.
255 * The name of the option
256 * @param booleanOption
258 * @return The given option
260 public Option<Boolean> addBooleanOption(String name, Option<Boolean> booleanOption) {
261 booleanOptions.put(name, booleanOption);
262 return booleanOption;
266 * Returns the boolean option with the given name.
269 * The name of the option
270 * @return The option, or {@code null} if there is no option with the given
273 public Option<Boolean> getBooleanOption(String name) {
274 return booleanOptions.get(name);
278 * Adds an {@link Integer} {@link Option}.
281 * The name of the option
282 * @param integerOption
284 * @return The given option
286 public Option<Integer> addIntegerOption(String name, Option<Integer> integerOption) {
287 integerOptions.put(name, integerOption);
288 return integerOption;
292 * Returns an {@link Integer} {@link Option}.
295 * The name of the integer option to get
296 * @return The integer option, or {@code null} if there is no option with
299 public Option<Integer> getIntegerOption(String name) {
300 return integerOptions.get(name);
304 * Adds a {@link String} {@link Option}.
307 * The name of the option
308 * @param stringOption
310 * @return The given option
312 public Option<String> addStringOption(String name, Option<String> stringOption) {
313 stringOptions.put(name, stringOption);
318 * Returns a {@link String} {@link Option}.
321 * The name of the string option to get
322 * @return The string option, or {@code null} if there is no option with the
325 public Option<String> getStringOption(String name) {
326 return stringOptions.get(name);
330 * Adds an {@link Enum} {@link Option}.
335 * The name of the option
338 * @return The given option
340 public <T extends Enum<T>> Option<T> addEnumOption(String name, Option<T> enumOption) {
341 enumOptions.put(name, enumOption);
346 * Returns a {@link Enum} {@link Option}. As the type can probably not be
347 * interred correctly you could help the compiler by calling this method
352 * options.<SomeEnum> getEnumOption("SomeEnumOption").get();
358 * The name of the option
359 * @return The enum option, or {@code null} if there is no enum option with
362 @SuppressWarnings("unchecked")
363 public <T extends Enum<T>> Option<T> getEnumOption(String name) {
364 return (Option<T>) enumOptions.get(name);