/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* 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 com.analog.lyric.options;
import java.io.Serializable;
import java.util.Comparator;
import net.jcip.annotations.Immutable;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* A unique key for looking up or setting a value from a {@link IOptionHolder}.
* <p>
* @param <T> is the type of the value that will be associated with the key. The type
* should either be {@link String}, a wrapped primitive type (e.g. {@link Double}, {@link Boolean}),
* or an immutable concrete implementation of {@link IOptionValue}.
* <p>
* Concrete instances should be public static final fields, with given {@link #name()}, preferably
* in a subclass of {@link OptionKeyDeclarer}.
* <p>
* {@link OptionKey} contains useful static methods for loading option keys, whether or not
* they are implemented as subclasses of that class.
* <p>
* @see OptionKey#forCanonicalName
* @see OptionKey#inClass(Class, String)
* @see OptionKey#canonicalName(IOptionKey)
* @see OptionKey#qualifiedName(IOptionKey)
*/
@Immutable
public interface IOptionKey<T extends Serializable> extends Serializable
{
/**
* Comparator that orders keys by name.
*
* @since 0.07
*/
public static enum CompareByName implements Comparator<IOptionKey<?>>
{
INSTANCE;
@NonNullByDefault(false)
@Override
public int compare(IOptionKey<?> key1, IOptionKey<?> key2)
{
return key1.name().compareTo(key2.name());
}
}
/**
* Identifies the option lookup method used for an option key.
*
* @since 0.08
*/
public static enum Lookup
{
/**
* Look up option values be searching delegates. This is the standard method.
*/
NONLOCAL,
/**
* Look up option values only locally.
*/
LOCAL;
}
/**
* Attempts to convert value to appropriate key value type.
* <p>
* This method should be able to convert values produced by {@link #convertToExternal}.
* <p>
* @param value a non-null value to be converted to the option's {@link #type}.
* @throws RuntimeException if value cannot be converted
* @since 0.07
*/
public abstract T convertToValue(@Nullable Object value);
/**
* Converts value to an external representation
* <p>
* Converts value to representation suitable for use in external environments
* such as MATLAB or Python. Acceptable output types include boxed primitive
* types, Strings, and arrays of the those.
* <p>
* It is expected that the returned value can be converted back to the original
* typed value using {@link #convertToValue}.
* <p>
* @param value
* @since 0.07
*/
public abstract @Nullable Object convertToExternal(T value);
/**
* Should be the class that contains the declaration of this instance.
*/
public abstract Class<?> getDeclaringClass();
/**
* Indicates whether this is a local option.
* <p>
* Local options are only looked up locally in the option holder and not its delegates.
* True if {@link #lookupMethod} is {@code LOCAL}.
* @since 0.08
*/
public abstract boolean local();
/**
* Identifies the lookup method used to retrieve option values for this key.
* @since 0.08
* @see #local
*/
public abstract Lookup lookupMethod();
/**
* The unqualified name of the option.
* <p>
* Should be a valid Java identifier, and should be the same as the name
* of the field that holds this instance.
*/
public abstract String name();
/**
* The type of the option's value, which should be the same as the type parameter {@code T}.
*/
public abstract Class<? extends T> type();
/**
* The default value of the option if not set. This must not be null!
*/
public abstract T defaultValue();
/**
* Returns the value of the option for the given {@code holder} or else its default value, if not set.
* <p>
* This should be implemented by invoking {@linkplain IOptionHolder#getOptionOrDefault getOptionOrDefault}
* on {@code holder}.
*/
public abstract T getOrDefault(IOptionHolder holder);
/**
* Returns the value of the option for the given {@code holder} or null if not set.
* <p>
* This should be implemented by invoking {@linkplain IOptionHolder#getOption getOption}
* on {@code holder}.
*/
public abstract @Nullable T get(IOptionHolder holder);
/**
* Set the option value locally on the given {@code holder}.
* <p>
* This should be implemented by invoking {@linkplain IOptionHolder#setOption(IOptionKey,Serializable) setOption}
* on {@code holder}.
*/
public abstract void set(IOptionHolder holder, T value);
/**
* Unset the option locally on the given {@code holder}.
* <p>
* This should be implemented by invoking {@linkplain IOptionHolder#unsetOption(IOptionKey) unsetOption}
* on {@code holder}.
*/
public abstract void unset(IOptionHolder holder);
/**
* Determine if value obtained locally from an option holder can be used by another option holder.
* <p>
* This method is called by implementations of {@link IOptionHolder#getOption(IOptionKey)} and
* related methods when determining whether or not to skip over a value found in a delegate option
* holder.
* <p>
* @param value is non-null value that has been set locally on some option holder
* @param delegator is the option holder from which the lookup originates.
* @return true if value can be used by {@code delegator}. Most implemtnations will simply return true.
* @since 0.08
*/
public boolean validForDelegator(T value, IOptionHolder delegator);
/**
* Validates value for this key.
* <p>
* This is invoked by implementations of {@link IOptionHolder#setOption} and can be
* overridden to put extra constraints on the value.
* <p>
* @param value is the value to be set on this option.
* @param optionHolder is the option holder on which the option is being set, if available.
* @return the {@code value} itself if valid otherwise throws an exception.
* @throws ClassCastException if {@code value} has the wrong type.
* @throws OptionValidationException if value is invalid.
* @since 0.07
*/
public T validate(T value, @Nullable IOptionHolder optionHolder);
}