All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xnio.OptionMap Maven / Gradle / Ivy

There is a newer version: 62
Show newest version
/*
 * 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 {@code null} keys or values are permitted.
 */
public final class OptionMap implements Iterable>, Serializable {

    private static final long serialVersionUID = 3632842565346928132L;

    private final Map, Object> value;

    private OptionMap(final Map, Object> value) {
        this.value = value;
    }

    /**
     * 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.
     *
     * @param option the option to get
     * @param  the type of the option
     * @return the option value, or {@code null} if it is not present
     */
    public  T get(Option 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.
     *
     * @param option the option to get
     * @param defaultValue the value to return if the option is not set
     * @param  the type of the option
     * @return the option value, or {@code null} if it is not present
     */
    public  T get(Option 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.
     *
     * @param option the option to get
     * @param defaultValue the default value if the option is not present
     * @return the result
     */
    public boolean get(Option 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.
     *
     * @param option the option to get
     * @param defaultValue the default value if the option is not present
     * @return the result
     */
    public int get(Option 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.
     *
     * @param option the option to get
     * @param defaultValue the default value if the option is not present
     * @return the result
     */
    public long get(Option option, long defaultValue) {
        final Object o = value.get(option);
        return o == null ? defaultValue : option.cast(o).longValue();
    }

    /**
     * Iterate over the options in this map.
     *
     * @return an iterator over the options
     */
    public Iterator> iterator() {
        return Collections.unmodifiableCollection(value.keySet()).iterator();
    }

    /**
     * Get the number of options stored in this map.
     *
     * @return the number of options
     */
    public int size() {
        return value.size();
    }

    /**
     * The empty option map.
     */
    public static final OptionMap EMPTY = new OptionMap(Collections., Object>emptyMap());

    /**
     * Create a new builder.
     *
     * @return a new builder
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * Create a single-valued option map.
     *
     * @param option the option to put in the map
     * @param value the option value
     * @param  the option value type
     * @return the option map
     *
     * @since 3.0
     */
    public static  OptionMap create(Option option, T value) {
        if (option == null) {
            throw msg.nullParameter("option");
        }
        if (value == null) {
            throw msg.nullParameter("value");
        }
        return new OptionMap(Collections., 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.
     *
     * @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  the first option value type
     * @param  the second option value type
     * @return the option map
     *
     * @since 3.0
     */
    public static  OptionMap create(Option option1, T1 value1, Option 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, Object> map = new IdentityHashMap, 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, Object>> iterator = value.entrySet().iterator();
        while (iterator.hasNext()) {
            final Map.Entry, 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.
     *
     * @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.
     *
     * @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.
     *
     * @return the hash code
     */
    public int hashCode() {
        return value.hashCode();
    }

    /**
     * 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 {
            Option option;
            T value;

            private OVPair(final Option option, final T value) {
                this.option = option;
                this.value = value;
            }
        }

        private List> list = new ArrayList>();

        /**
         * Set a key-value pair, parsing the value from the given string.
         *
         * @param key the key
         * @param stringValue the string value
         * @param  the option type
         * @return this builder
         */
        public  Builder parse(Option 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.
         *
         * @param key the key
         * @param stringValue the string value
         * @param classLoader the class loader to use for parsing the value
         * @param  the option type
         * @return this builder
         */
        public  Builder parse(Option 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. * * @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. * * @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. * * @param key the key * @param value the value * @param the option type * @return this builder */ public Builder set(Option key, T value) { if (key == null) { throw msg.nullParameter("key"); } if (value == null) { throw msg.nullParameter("value"); } list.add(new OVPair(key, value)); return this; } /** * Set an int value for an Integer key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, int value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Integer.valueOf(value))); return this; } /** * Set int values for an Integer sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> 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>(key, Sequence.of(a))); return this; } /** * Set a long value for a Long key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, long value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Long.valueOf(value))); return this; } /** * Set long values for a Long sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> 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>(key, Sequence.of(a))); return this; } /** * Set a boolean value for a Boolean key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, boolean value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Boolean.valueOf(value))); return this; } /** * Set boolean values for an Boolean sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> 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>(key, Sequence.of(a))); return this; } /** * Set a key-value pair, where the value is a sequence type. * * @param key the key * @param values the values * @param the option type * @return this builder */ public Builder setSequence(Option> key, T... values) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair>(key, Sequence.of(values))); return this; } private void copy(Map map, Option option) { set(option, option.cast(map.get(option))); } /** * 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 void copy(OptionMap optionMap, Option 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. * * @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. * * @return the new immutable option map */ public OptionMap getMap() { final List> list = this.list; if (list.size() == 0) { return EMPTY; } else if (list.size() == 1) { final OVPair pair = list.get(0); return new OptionMap(Collections., Object>singletonMap(pair.option, pair.value)); } else { final Map, Object> map = new IdentityHashMap, Object>(); for (OVPair ovPair : list) { map.put(ovPair.option, ovPair.value); } return new OptionMap(map); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy