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

org.apache.flink.configuration.Configuration Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.flink.configuration;

import org.apache.flink.annotation.Public;
import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.core.io.IOReadableWritable;
import org.apache.flink.core.memory.DataInputView;
import org.apache.flink.core.memory.DataOutputView;
import org.apache.flink.types.StringValue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * Lightweight configuration object which stores key/value pairs.
 */
@Public
public class Configuration extends ExecutionConfig.GlobalJobParameters
		implements IOReadableWritable, java.io.Serializable, Cloneable {

	private static final long serialVersionUID = 1L;

	private static final byte TYPE_STRING = 0;
	private static final byte TYPE_INT = 1;
	private static final byte TYPE_LONG = 2;
	private static final byte TYPE_BOOLEAN = 3;
	private static final byte TYPE_FLOAT = 4;
	private static final byte TYPE_DOUBLE = 5;
	private static final byte TYPE_BYTES = 6;

	/** The log object used for debugging. */
	private static final Logger LOG = LoggerFactory.getLogger(Configuration.class);


	/** Stores the concrete key/value pairs of this configuration object. */
	protected final HashMap confData;

	// --------------------------------------------------------------------------------------------

	/**
	 * Creates a new empty configuration.
	 */
	public Configuration() {
		this.confData = new HashMap<>();
	}

	/**
	 * Creates a new configuration with the copy of the given configuration.
	 *
	 * @param other The configuration to copy the entries from.
	 */
	public Configuration(Configuration other) {
		this.confData = new HashMap<>(other.confData);
	}

	// --------------------------------------------------------------------------------------------

	/**
	 * Returns the class associated with the given key as a string.
	 *
	 * @param  The type of the class to return.

	 * @param key The key pointing to the associated value
	 * @param defaultValue The optional default value returned if no entry exists
	 * @param classLoader The class loader used to resolve the class.
	 *
	 * @return The value associated with the given key, or the default value, if to entry for the key exists.
	 */
	@SuppressWarnings("unchecked")
	public  Class getClass(String key, Class defaultValue, ClassLoader classLoader) throws ClassNotFoundException {
		Object o = getRawValue(key);
		if (o == null) {
			return (Class) defaultValue;
		}

		if (o.getClass() == String.class) {
			return (Class) Class.forName((String) o, true, classLoader);
		}

		LOG.warn("Configuration cannot evaluate value " + o + " as a class name");
		return (Class) defaultValue;
	}

	/**
	 * Adds the given key/value pair to the configuration object. The class can be retrieved by invoking
	 * {@link #getClass(String, Class, ClassLoader)} if it is in the scope of the class loader on the caller.
	 *
	 * @param key The key of the pair to be added
	 * @param klazz The value of the pair to be added
	 * @see #getClass(String, Class, ClassLoader)
	 */
	public void setClass(String key, Class klazz) {
		setValueInternal(key, klazz.getName());
	}

	/**
	 * Returns the value associated with the given key as a string.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public String getString(String key, String defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		} else {
			return o.toString();
		}
	}

	/**
	 * Returns the value associated with the given config option as a string.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public String getString(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return o == null ? null : o.toString();
	}

	/**
	 * Returns the value associated with the given config option as a string.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public String getString(ConfigOption configOption, String overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		return o == null ? overrideDefault : o.toString();
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setString(String key, String value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setString(ConfigOption key, String value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as an integer.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public int getInteger(String key, int defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}

		return convertToInt(o, defaultValue);
	}

	/**
	 * Returns the value associated with the given config option as an integer.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public int getInteger(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return convertToInt(o, configOption.defaultValue());
	}

	/**
	 * Returns the value associated with the given config option as an integer.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @param overrideDefault The value to return if no value was mapper for any key of the option
	 * @return the configured value associated with the given config option, or the overrideDefault
	 */
	@PublicEvolving
	public int getInteger(ConfigOption configOption, int overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		if (o == null) {
			return overrideDefault;
		}
		return convertToInt(o, configOption.defaultValue());
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setInteger(String key, int value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setInteger(ConfigOption key, int value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as a long.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public long getLong(String key, long defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}

		return convertToLong(o, defaultValue);
	}

	/**
	 * Returns the value associated with the given config option as a long integer.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public long getLong(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return convertToLong(o, configOption.defaultValue());
	}

	/**
	 * Returns the value associated with the given config option as a long integer.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @param overrideDefault The value to return if no value was mapper for any key of the option
	 * @return the configured value associated with the given config option, or the overrideDefault
	 */
	@PublicEvolving
	public long getLong(ConfigOption configOption, long overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		if (o == null) {
			return overrideDefault;
		}
		return convertToLong(o, configOption.defaultValue());
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setLong(String key, long value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setLong(ConfigOption key, long value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as a boolean.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public boolean getBoolean(String key, boolean defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}

		return convertToBoolean(o);
	}

	/**
	 * Returns the value associated with the given config option as a boolean.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public boolean getBoolean(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return convertToBoolean(o);
	}

	/**
	 * Returns the value associated with the given config option as a boolean.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @param overrideDefault The value to return if no value was mapper for any key of the option
	 * @return the configured value associated with the given config option, or the overrideDefault
	 */
	@PublicEvolving
	public boolean getBoolean(ConfigOption configOption, boolean overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		if (o == null) {
			return overrideDefault;
		}
		return convertToBoolean(o);
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setBoolean(String key, boolean value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setBoolean(ConfigOption key, boolean value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as a float.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public float getFloat(String key, float defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}

		return convertToFloat(o, defaultValue);
	}

	/**
	 * Returns the value associated with the given config option as a float.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public float getFloat(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return convertToFloat(o, configOption.defaultValue());
	}

	/**
	 * Returns the value associated with the given config option as a float.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @param overrideDefault The value to return if no value was mapper for any key of the option
	 * @return the configured value associated with the given config option, or the overrideDefault
	 */
	@PublicEvolving
	public float getFloat(ConfigOption configOption, float overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		if (o == null) {
			return overrideDefault;
		}
		return convertToFloat(o, configOption.defaultValue());
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setFloat(String key, float value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setFloat(ConfigOption key, float value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as a double.
	 *
	 * @param key
	 *        the key pointing to the associated value
	 * @param defaultValue
	 *        the default value which is returned in case there is no value associated with the given key
	 * @return the (default) value associated with the given key
	 */
	public double getDouble(String key, double defaultValue) {
		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}

		return convertToDouble(o, defaultValue);
	}

	/**
	 * Returns the value associated with the given config option as a {@code double}.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public double getDouble(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return convertToDouble(o, configOption.defaultValue());
	}

	/**
	 * Returns the value associated with the given config option as a {@code double}.
	 * If no value is mapped under any key of the option, it returns the specified
	 * default instead of the option's default value.
	 *
	 * @param configOption The configuration option
	 * @param overrideDefault The value to return if no value was mapper for any key of the option
	 * @return the configured value associated with the given config option, or the overrideDefault
	 */
	@PublicEvolving
	public double getDouble(ConfigOption configOption, double overrideDefault) {
		Object o = getRawValueFromOption(configOption);
		if (o == null) {
			return overrideDefault;
		}
		return convertToDouble(o, configOption.defaultValue());
	}

	/**
	 * Adds the given key/value pair to the configuration object.
	 *
	 * @param key
	 *        the key of the key/value pair to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	public void setDouble(String key, double value) {
		setValueInternal(key, value);
	}

	/**
	 * Adds the given value to the configuration object.
	 * The main key of the config option will be used to map the value.
	 *
	 * @param key
	 *        the option specifying the key to be added
	 * @param value
	 *        the value of the key/value pair to be added
	 */
	@PublicEvolving
	public void setDouble(ConfigOption key, double value) {
		setValueInternal(key.key(), value);
	}

	/**
	 * Returns the value associated with the given key as a byte array.
	 *
	 * @param key
	 *        The key pointing to the associated value.
	 * @param defaultValue
	 *        The default value which is returned in case there is no value associated with the given key.
	 * @return the (default) value associated with the given key.
	 */
	@SuppressWarnings("EqualsBetweenInconvertibleTypes")
	public byte[] getBytes(String key, byte[] defaultValue) {

		Object o = getRawValue(key);
		if (o == null) {
			return defaultValue;
		}
		else if (o.getClass().equals(byte[].class)) {
			return (byte[]) o;
		}
		else {
			LOG.warn("Configuration cannot evaluate value {} as a byte[] value", o);
			return defaultValue;
		}
	}

	/**
	 * Adds the given byte array to the configuration object. If key is null then nothing is added.
	 *
	 * @param key
	 *        The key under which the bytes are added.
	 * @param bytes
	 *        The bytes to be added.
	 */
	public void setBytes(String key, byte[] bytes) {
		setValueInternal(key, bytes);
	}

	/**
	 * Returns the value associated with the given config option as a string.
	 *
	 * @param configOption The configuration option
	 * @return the (default) value associated with the given config option
	 */
	@PublicEvolving
	public String getValue(ConfigOption configOption) {
		Object o = getValueOrDefaultFromOption(configOption);
		return o == null ? null : o.toString();
	}

	// --------------------------------------------------------------------------------------------

	/**
	 * Returns the keys of all key/value pairs stored inside this
	 * configuration object.
	 *
	 * @return the keys of all key/value pairs stored inside this configuration object
	 */
	public Set keySet() {
		synchronized (this.confData) {
			return new HashSet<>(this.confData.keySet());
		}
	}

	/**
	 * Adds all entries in this {@code Configuration} to the given {@link Properties}.
	 */
	public void addAllToProperties(Properties props) {
		synchronized (this.confData) {
			for (Map.Entry entry : this.confData.entrySet()) {
				props.put(entry.getKey(), entry.getValue());
			}
		}
	}

	public void addAll(Configuration other) {
		synchronized (this.confData) {
			synchronized (other.confData) {
				this.confData.putAll(other.confData);
			}
		}
	}

	public void addAll(Map other) {
		synchronized (this.confData) {
			this.confData.putAll(other);
		}
	}

	/**
	 * Adds all entries from the given configuration into this configuration. The keys
	 * are prepended with the given prefix.
	 *
	 * @param other
	 *        The configuration whose entries are added to this configuration.
	 * @param prefix
	 *        The prefix to prepend.
	 */
	public void addAll(Configuration other, String prefix) {
		final StringBuilder bld = new StringBuilder();
		bld.append(prefix);
		final int pl = bld.length();

		synchronized (this.confData) {
			synchronized (other.confData) {
				for (Map.Entry entry : other.confData.entrySet()) {
					bld.setLength(pl);
					bld.append(entry.getKey());
					this.confData.put(bld.toString(), entry.getValue());
				}
			}
		}
	}

	@Override
	public Configuration clone() {
		Configuration config = new Configuration();
		config.addAll(this);

		return config;
	}

	/**
	 * Checks whether there is an entry with the specified key.
	 *
	 * @param key key of entry
	 * @return true if the key is stored, false otherwise
	 */
	public boolean containsKey(String key){
		synchronized (this.confData){
			return this.confData.containsKey(key);
		}
	}

	/**
	 * Checks whether there is an entry for the given config option.
	 *
	 * @param configOption The configuration option
	 *
	 * @return true if a valid (current or deprecated) key of the config option is stored,
	 * false otherwise
	 */
	@PublicEvolving
	public boolean contains(ConfigOption configOption) {
		synchronized (this.confData){
			// first try the current key
			if (this.confData.containsKey(configOption.key())) {
				return true;
			}
			else if (configOption.hasDeprecatedKeys()) {
				// try the deprecated keys
				for (String deprecatedKey : configOption.deprecatedKeys()) {
					if (this.confData.containsKey(deprecatedKey)) {
						LOG.warn("Config uses deprecated configuration key '{}' instead of proper key '{}'",
							deprecatedKey, configOption.key());
						return true;
					}
				}
			}

			return false;
		}
	}

	public void remove(String key) {
		synchronized (this.confData) {
			this.confData.remove(key);
		}
	}

	public void remove(ConfigOption configOption) {
		synchronized (this.confData) {
			this.confData.remove(configOption.key());
		}
	}

	// --------------------------------------------------------------------------------------------

	@Override
	public Map toMap() {
		synchronized (this.confData){
			Map ret = new HashMap<>(this.confData.size());
			for (Map.Entry entry : confData.entrySet()) {
				ret.put(entry.getKey(), entry.getValue().toString());
			}
			return ret;
		}
	}


	// --------------------------------------------------------------------------------------------

	 void setValueInternal(String key, T value) {
		if (key == null) {
			throw new NullPointerException("Key must not be null.");
		}
		if (value == null) {
			throw new NullPointerException("Value must not be null.");
		}

		synchronized (this.confData) {
			this.confData.put(key, value);
		}
	}

	private Object getRawValue(String key) {
		if (key == null) {
			throw new NullPointerException("Key must not be null.");
		}

		synchronized (this.confData) {
			return this.confData.get(key);
		}
	}

	private Object getRawValueFromOption(ConfigOption configOption) {
		// first try the current key
		Object o = getRawValue(configOption.key());

		if (o != null) {
			// found a value for the current proper key
			return o;
		}
		else if (configOption.hasDeprecatedKeys()) {
			// try the deprecated keys
			for (String deprecatedKey : configOption.deprecatedKeys()) {
				Object oo = getRawValue(deprecatedKey);
				if (oo != null) {
					LOG.warn("Config uses deprecated configuration key '{}' instead of proper key '{}'",
							deprecatedKey, configOption.key());
					return oo;
				}
			}
		}

		return null;
	}

	private Object getValueOrDefaultFromOption(ConfigOption configOption) {
		Object o = getRawValueFromOption(configOption);
		return o != null ? o : configOption.defaultValue();
	}

	// --------------------------------------------------------------------------------------------
	//  Type conversion
	// --------------------------------------------------------------------------------------------

	private int convertToInt(Object o, int defaultValue) {
		if (o.getClass() == Integer.class) {
			return (Integer) o;
		}
		else if (o.getClass() == Long.class) {
			long value = (Long) o;
			if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
				return (int) value;
			} else {
				LOG.warn("Configuration value {} overflows/underflows the integer type.", value);
				return defaultValue;
			}
		}
		else {
			try {
				return Integer.parseInt(o.toString());
			}
			catch (NumberFormatException e) {
				LOG.warn("Configuration cannot evaluate value {} as an integer number", o);
				return defaultValue;
			}
		}
	}

	private long convertToLong(Object o, long defaultValue) {
		if (o.getClass() == Long.class) {
			return (Long) o;
		}
		else if (o.getClass() == Integer.class) {
			return ((Integer) o).longValue();
		}
		else {
			try {
				return Long.parseLong(o.toString());
			}
			catch (NumberFormatException e) {
				LOG.warn("Configuration cannot evaluate value " + o + " as a long integer number");
				return defaultValue;
			}
		}
	}

	private boolean convertToBoolean(Object o) {
		if (o.getClass() == Boolean.class) {
			return (Boolean) o;
		}
		else {
			return Boolean.parseBoolean(o.toString());
		}
	}

	private float convertToFloat(Object o, float defaultValue) {
		if (o.getClass() == Float.class) {
			return (Float) o;
		}
		else if (o.getClass() == Double.class) {
			double value = ((Double) o);
			if (value == 0.0
					|| (value >= Float.MIN_VALUE && value <= Float.MAX_VALUE)
					|| (value >= -Float.MAX_VALUE && value <= -Float.MIN_VALUE)) {
				return (float) value;
			} else {
				LOG.warn("Configuration value {} overflows/underflows the float type.", value);
				return defaultValue;
			}
		}
		else {
			try {
				return Float.parseFloat(o.toString());
			}
			catch (NumberFormatException e) {
				LOG.warn("Configuration cannot evaluate value {} as a float value", o);
				return defaultValue;
			}
		}
	}

	private double convertToDouble(Object o, double defaultValue) {
		if (o.getClass() == Double.class) {
			return (Double) o;
		}
		else if (o.getClass() == Float.class) {
			return ((Float) o).doubleValue();
		}
		else {
			try {
				return Double.parseDouble(o.toString());
			}
			catch (NumberFormatException e) {
				LOG.warn("Configuration cannot evaluate value {} as a double value", o);
				return defaultValue;
			}
		}
	}

	// --------------------------------------------------------------------------------------------
	//  Serialization
	// --------------------------------------------------------------------------------------------

	@Override
	public void read(DataInputView in) throws IOException {
		synchronized (this.confData) {
			final int numberOfProperties = in.readInt();

			for (int i = 0; i < numberOfProperties; i++) {
				String key = StringValue.readString(in);
				Object value;

				byte type = in.readByte();
				switch (type) {
					case TYPE_STRING:
						value = StringValue.readString(in);
						break;
					case TYPE_INT:
						value = in.readInt();
						break;
					case TYPE_LONG:
						value = in.readLong();
						break;
					case TYPE_FLOAT:
						value = in.readFloat();
						break;
					case TYPE_DOUBLE:
						value = in.readDouble();
						break;
					case TYPE_BOOLEAN:
						value = in.readBoolean();
						break;
					case TYPE_BYTES:
						byte[] bytes = new byte[in.readInt()];
						in.readFully(bytes);
						value = bytes;
						break;
					default:
						throw new IOException("Unrecognized type: " + type);
				}

				this.confData.put(key, value);
			}
		}
	}

	@Override
	public void write(final DataOutputView out) throws IOException {
		synchronized (this.confData) {
			out.writeInt(this.confData.size());

			for (Map.Entry entry : this.confData.entrySet()) {
				String key = entry.getKey();
				Object val = entry.getValue();

				StringValue.writeString(key, out);
				Class clazz = val.getClass();

				if (clazz == String.class) {
					out.write(TYPE_STRING);
					StringValue.writeString((String) val, out);
				}
				else if (clazz == Integer.class) {
					out.write(TYPE_INT);
					out.writeInt((Integer) val);
				}
				else if (clazz == Long.class) {
					out.write(TYPE_LONG);
					out.writeLong((Long) val);
				}
				else if (clazz == Float.class) {
					out.write(TYPE_FLOAT);
					out.writeFloat((Float) val);
				}
				else if (clazz == Double.class) {
					out.write(TYPE_DOUBLE);
					out.writeDouble((Double) val);
				}
				else if (clazz == byte[].class) {
					out.write(TYPE_BYTES);
					byte[] bytes = (byte[]) val;
					out.writeInt(bytes.length);
					out.write(bytes);
				}
				else if (clazz == Boolean.class) {
					out.write(TYPE_BOOLEAN);
					out.writeBoolean((Boolean) val);
				}
				else {
					throw new IllegalArgumentException("Unrecognized type");
				}
			}
		}
	}

	// --------------------------------------------------------------------------------------------

	@Override
	public int hashCode() {
		int hash = 0;
		for (String s : this.confData.keySet()) {
			hash ^= s.hashCode();
		}
		return hash;
	}

	@SuppressWarnings("EqualsBetweenInconvertibleTypes")
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		else if (obj instanceof Configuration) {
			Map otherConf = ((Configuration) obj).confData;

			for (Map.Entry e : this.confData.entrySet()) {
				Object thisVal = e.getValue();
				Object otherVal = otherConf.get(e.getKey());

				if (!thisVal.getClass().equals(byte[].class)) {
					if (!thisVal.equals(otherVal)) {
						return false;
					}
				} else if (otherVal.getClass().equals(byte[].class)) {
					if (!Arrays.equals((byte[]) thisVal, (byte[]) otherVal)) {
						return false;
					}
				} else {
					return false;
				}
			}

			return true;
		}
		else {
			return false;
		}
	}

	@Override
	public String toString() {
		return this.confData.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy