/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2009 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xnio;

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Properties;
import java.io.Serializable;

import static org.xnio._private.Messages.msg;
import static org.xnio._private.Messages.optionParseMsg;

An immutable map of options to option values. No null keys or values are permitted.
/** * An immutable map of options to option values. No {@code null} keys or values are permitted. */
public final class OptionMap implements Iterable<Option<?>>, Serializable { private static final long serialVersionUID = 3632842565346928132L; private final Map<Option<?>, Object> value; private OptionMap(final Map<Option<?>, Object> value) { this.value = value; }
Determine whether this option map contains the given option.
Params:
  • option – the option to check
Returns:true if the option is present in the option map
/** * Determine whether this option map contains the given option. * * @param option the option to check * @return {@code true} if the option is present in the option map */
public boolean contains(Option<?> option) { return value.containsKey(option); }
Get the value of an option from this option map.
Params:
  • option – the option to get
Type parameters:
  • <T> – the type of the option
Returns:the option value, or null if it is not present
/** * Get the value of an option from this option map. * * @param option the option to get * @param <T> the type of the option * @return the option value, or {@code null} if it is not present */
public <T> T get(Option<T> option) { return option.cast(value.get(option)); }
Get the value of an option from this option map, with a specified default if the value is missing.
Params:
  • option – the option to get
  • defaultValue – the value to return if the option is not set
Type parameters:
  • <T> – the type of the option
Returns:the option value, or null if it is not present
/** * Get the value of an option from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the value to return if the option is not set * @param <T> the type of the option * @return the option value, or {@code null} if it is not present */
public <T> T get(Option<T> option, T defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o); }
Get a boolean value from this option map, with a specified default if the value is missing.
Params:
  • option – the option to get
  • defaultValue – the default value if the option is not present
Returns:the result
/** * Get a boolean value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */
public boolean get(Option<Boolean> option, boolean defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).booleanValue(); }
Get a int value from this option map, with a specified default if the value is missing.
Params:
  • option – the option to get
  • defaultValue – the default value if the option is not present
Returns:the result
/** * Get a int value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */
public int get(Option<Integer> option, int defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).intValue(); }
Get a long value from this option map, with a specified default if the value is missing.
Params:
  • option – the option to get
  • defaultValue – the default value if the option is not present
Returns:the result
/** * Get a long value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */
public long get(Option<Long> option, long defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).longValue(); }
Iterate over the options in this map.
Returns:an iterator over the options
/** * Iterate over the options in this map. * * @return an iterator over the options */
public Iterator<Option<?>> iterator() { return Collections.unmodifiableCollection(value.keySet()).iterator(); }
Get the number of options stored in this map.
Returns:the number of options
/** * Get the number of options stored in this map. * * @return the number of options */
public int size() { return value.size(); }
The empty option map.
/** * The empty option map. */
public static final OptionMap EMPTY = new OptionMap(Collections.<Option<?>, Object>emptyMap());
Create a new builder.
Returns:a new builder
/** * Create a new builder. * * @return a new builder */
public static Builder builder() { return new Builder(); }
Create a single-valued option map.
Params:
  • option – the option to put in the map
  • value – the option value
Type parameters:
  • <T> – the option value type
Returns:the option map
Since:3.0
/** * Create a single-valued option map. * * @param option the option to put in the map * @param value the option value * @param <T> the option value type * @return the option map * * @since 3.0 */
public static <T> OptionMap create(Option<T> option, T value) { if (option == null) { throw msg.nullParameter("option"); } if (value == null) { throw msg.nullParameter("value"); } return new OptionMap(Collections.<Option<?>, Object>singletonMap(option, option.cast(value))); }
Create a two-valued option map. If both options are the same key, then only the second one is added to the map.
Params:
  • option1 – the first option to put in the map
  • value1 – the first option value
  • option2 – the second option to put in the map
  • value2 – the second option value
Type parameters:
  • <T1> – the first option value type
  • <T2> – the second option value type
Returns:the option map
Since:3.0
/** * Create a two-valued option map. If both options are the same key, then only the second one is added * to the map. * * @param option1 the first option to put in the map * @param value1 the first option value * @param option2 the second option to put in the map * @param value2 the second option value * @param <T1> the first option value type * @param <T2> the second option value type * @return the option map * * @since 3.0 */
public static <T1, T2> OptionMap create(Option<T1> option1, T1 value1, Option<T2> option2, T2 value2) { if (option1 == null) { throw msg.nullParameter("option1"); } if (value1 == null) { throw msg.nullParameter("value1"); } if (option2 == null) { throw msg.nullParameter("option2"); } if (value2 == null) { throw msg.nullParameter("value2"); } if (option1 == option2) { return create(option2, value2); } final IdentityHashMap<Option<?>, Object> map = new IdentityHashMap<Option<?>, Object>(2); map.put(option1, value1); map.put(option2, value2); return new OptionMap(map); } public String toString() { final StringBuilder builder = new StringBuilder(); builder.append('{'); final Iterator<Map.Entry<Option<?>, Object>> iterator = value.entrySet().iterator(); while (iterator.hasNext()) { final Map.Entry<Option<?>, Object> entry = iterator.next(); builder.append(entry.getKey()).append("=>").append(entry.getValue()); if (iterator.hasNext()) { builder.append(','); } } builder.append('}'); return builder.toString(); }
Determine whether this option map is equal to another.
Params:
  • other – the other option map
Returns:true if they are equal, false otherwise
/** * Determine whether this option map is equal to another. * * @param other the other option map * @return {@code true} if they are equal, {@code false} otherwise */
public boolean equals(Object other) { return other instanceof OptionMap && equals((OptionMap)other); }
Determine whether this option map is equal to another.
Params:
  • other – the other option map
Returns:true if they are equal, false otherwise
/** * Determine whether this option map is equal to another. * * @param other the other option map * @return {@code true} if they are equal, {@code false} otherwise */
public boolean equals(OptionMap other) { return this == other || other != null && value.equals(other.value); }
Get the hash code for this option map.
Returns:the hash code
/** * Get the hash code for this option map. * * @return the hash code */
public int hashCode() { return value.hashCode(); }
A builder for immutable option maps. Create an instance with the OptionMap.builder() method.
/** * A builder for immutable option maps. Create an instance with the {@link OptionMap#builder()} method. */
public static final class Builder { private Builder() { } private static class OVPair<T> { Option<T> option; T value; private OVPair(final Option<T> option, final T value) { this.option = option; this.value = value; } } private List<OVPair<?>> list = new ArrayList<OVPair<?>>();
Set a key-value pair, parsing the value from the given string.
Params:
  • key – the key
  • stringValue – the string value
Type parameters:
  • <T> – the option type
Returns:this builder
/** * Set a key-value pair, parsing the value from the given string. * * @param key the key * @param stringValue the string value * @param <T> the option type * @return this builder */
public <T> Builder parse(Option<T> key, String stringValue) { set(key, key.parseValue(stringValue, key.getClass().getClassLoader())); return this; }
Set a key-value pair, parsing the value from the given string.
Params:
  • key – the key
  • stringValue – the string value
  • classLoader – the class loader to use for parsing the value
Type parameters:
  • <T> – the option type
Returns:this builder
/** * Set a key-value pair, parsing the value from the given string. * * @param key the key * @param stringValue the string value * @param classLoader the class loader to use for parsing the value * @param <T> the option type * @return this builder */
public <T> Builder parse(Option<T> key, String stringValue, ClassLoader classLoader) { set(key, key.parseValue(stringValue, classLoader)); return this; }
Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; the remainder of the property key (after the prefix) is the option name, and the value is the option value.

If the prefix does not end with '.' character, a '.' will be appended to it before parsing.

Params:
  • props – the properties to read
  • prefix – the prefix
  • optionClassLoader – the class loader to use to resolve option names
Returns:this builder
/** * Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; * the remainder of the property key (after the prefix) is the option name, and the value is the option value. * <p>If the prefix does not end with '.' character, a '.' will be appended to it before parsing. * * @param props the properties to read * @param prefix the prefix * @param optionClassLoader the class loader to use to resolve option names * @return this builder */
public Builder parseAll(Properties props, String prefix, ClassLoader optionClassLoader) { if (! prefix.endsWith(".")) { prefix = prefix + "."; } for (String name : props.stringPropertyNames()) { if (name.startsWith(prefix)) { final String optionName = name.substring(prefix.length()); try { final Option<?> option = Option.fromString(optionName, optionClassLoader); parse(option, props.getProperty(name), optionClassLoader); } catch (IllegalArgumentException e) { optionParseMsg.invalidOptionInProperty(optionName, name, e); } } } return this; }
Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; the remainder of the property key (after the prefix) is the option name, and the value is the option value.

If the prefix does not end with '.' character, a '.' will be appended to it before parsing.

Params:
  • props – the properties to read
  • prefix – the prefix
Returns:this builder
/** * Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; * the remainder of the property key (after the prefix) is the option name, and the value is the option value. *<p>If the prefix does not end with '.' character, a '.' will be appended to it before parsing. * * @param props the properties to read * @param prefix the prefix * @return this builder */
public Builder parseAll(Properties props, String prefix) { if (! prefix.endsWith(".")) { prefix = prefix + "."; } for (String name : props.stringPropertyNames()) { if (name.startsWith(prefix)) { final String optionName = name.substring(prefix.length()); try { final Option<?> option = Option.fromString(optionName, getClass().getClassLoader()); parse(option, props.getProperty(name)); } catch (IllegalArgumentException e) { optionParseMsg.invalidOptionInProperty(optionName, name, e); } } } return this; }
Set a key-value pair.
Params:
  • key – the key
  • value – the value
Type parameters:
  • <T> – the option type
Returns:this builder
/** * Set a key-value pair. * * @param key the key * @param value the value * @param <T> the option type * @return this builder */
public <T> Builder set(Option<T> key, T value) { if (key == null) { throw msg.nullParameter("key"); } if (value == null) { throw msg.nullParameter("value"); } list.add(new OVPair<T>(key, value)); return this; }
Set an int value for an Integer key.
Params:
  • key – the option
  • value – the value
Returns:this builder
/** * Set an int value for an Integer key. * * @param key the option * @param value the value * @return this builder */
public Builder set(Option<Integer> key, int value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair<Integer>(key, Integer.valueOf(value))); return this; }
Set int values for an Integer sequence key.
Params:
  • key – the key
  • values – the values
Returns:this builder
/** * Set int values for an Integer sequence key. * * @param key the key * @param values the values * @return this builder */
public Builder setSequence(Option<Sequence<Integer>> key, int... values) { if (key == null) { throw msg.nullParameter("key"); } Integer[] a = new Integer[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Integer.valueOf(values[i]); } list.add(new OVPair<Sequence<Integer>>(key, Sequence.of(a))); return this; }
Set a long value for a Long key.
Params:
  • key – the option
  • value – the value
Returns:this builder
/** * Set a long value for a Long key. * * @param key the option * @param value the value * @return this builder */
public Builder set(Option<Long> key, long value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair<Long>(key, Long.valueOf(value))); return this; }
Set long values for a Long sequence key.
Params:
  • key – the key
  • values – the values
Returns:this builder
/** * Set long values for a Long sequence key. * * @param key the key * @param values the values * @return this builder */
public Builder setSequence(Option<Sequence<Long>> key, long... values) { if (key == null) { throw msg.nullParameter("key"); } Long[] a = new Long[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Long.valueOf(values[i]); } list.add(new OVPair<Sequence<Long>>(key, Sequence.of(a))); return this; }
Set a boolean value for a Boolean key.
Params:
  • key – the option
  • value – the value
Returns:this builder
/** * Set a boolean value for a Boolean key. * * @param key the option * @param value the value * @return this builder */
public Builder set(Option<Boolean> key, boolean value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair<Boolean>(key, Boolean.valueOf(value))); return this; }
Set boolean values for an Boolean sequence key.
Params:
  • key – the key
  • values – the values
Returns:this builder
/** * Set boolean values for an Boolean sequence key. * * @param key the key * @param values the values * @return this builder */
public Builder setSequence(Option<Sequence<Boolean>> key, boolean... values) { if (key == null) { throw msg.nullParameter("key"); } Boolean[] a = new Boolean[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Boolean.valueOf(values[i]); } list.add(new OVPair<Sequence<Boolean>>(key, Sequence.of(a))); return this; }
Set a key-value pair, where the value is a sequence type.
Params:
  • key – the key
  • values – the values
Type parameters:
  • <T> – the option type
Returns:this builder
/** * Set a key-value pair, where the value is a sequence type. * * @param key the key * @param values the values * @param <T> the option type * @return this builder */
public <T> Builder setSequence(Option<Sequence<T>> key, T... values) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair<Sequence<T>>(key, Sequence.of(values))); return this; } private <T> void copy(Map<?, ?> map, Option<T> option) { set(option, option.cast(map.get(option))); }
Add all the entries of a map. Any keys of the map which are not valid Options, or whose values are not valid arguments for the given Option, will cause an exception to be thrown. Any keys which occur more than once in this builder will be overwritten with the last occurring value.
Params:
  • map – the map
Throws:
Returns:this builder
/** * Add all the entries of a map. Any keys of the map which are not valid {@link Option}s, or whose * values are not valid arguments for the given {@code Option}, will cause an exception to be thrown. * Any keys which occur more than once in this builder will be overwritten with the last occurring value. * * @param map the map * @return this builder * @throws ClassCastException if any entries of the map are not valid option-value pairs */
public Builder add(Map<?, ?> map) throws ClassCastException { for (Object key : map.keySet()) { final Option<?> option = Option.class.cast(key); copy(map, option); } return this; } private <T> void copy(OptionMap optionMap, Option<T> option) { set(option, optionMap.get(option)); }
Add all entries from an existing option map to the one being built. Any keys which occur more than once in this builder will be overwritten with the last occurring value.
Params:
  • optionMap – the original option map
Returns:this builder
/** * Add all entries from an existing option map to the one being built. * Any keys which occur more than once in this builder will be overwritten with the last occurring value. * * @param optionMap the original option map * @return this builder */
public Builder addAll(OptionMap optionMap) { for (Option<?> option : optionMap) { copy(optionMap, option); } return this; }
Build a map that reflects the current state of this builder.
Returns:the new immutable option map
/** * Build a map that reflects the current state of this builder. * * @return the new immutable option map */
public OptionMap getMap() { final List<OVPair<?>> list = this.list; if (list.size() == 0) { return EMPTY; } else if (list.size() == 1) { final OVPair<?> pair = list.get(0); return new OptionMap(Collections.<Option<?>, Object>singletonMap(pair.option, pair.value)); } else { final Map<Option<?>, Object> map = new IdentityHashMap<Option<?>, Object>(); for (OVPair<?> ovPair : list) { map.put(ovPair.option, ovPair.value); } return new OptionMap(map); } } } }