/******************************************************************************* * Copyright 2015 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.dimple.schedulers; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.collect.ConstructorRegistry; import com.analog.lyric.dimple.environment.DimpleEnvironment; import com.analog.lyric.dimple.events.IDimpleEventSource; import com.analog.lyric.dimple.model.core.FactorGraph; import com.analog.lyric.dimple.schedulers.validator.ScheduleValidatorOptionKey; import com.analog.lyric.dimple.solvers.interfaces.ISolverFactorGraph; import com.analog.lyric.options.IOptionHolder; import com.analog.lyric.options.OptionKey; import com.analog.lyric.options.OptionValidationException; /** * Option key type for schedulers. * <p> * Unlike most options, scheduler options can hold mutable values and the {@link #defaultValue()} * is not a singleton constant but a newly created object. * <p> * @since 0.08 * @author Christopher Barber */ public class SchedulerOptionKey extends OptionKey<IScheduler> { private static final long serialVersionUID = 1L; /*------- * State */ private final Class<? extends IScheduler> _defaultSchedulerClass; private final @Nullable ScheduleValidatorOptionKey _validatorKey; /*-------------- * Construction */ /** * Constructs a scheduler option key. * @param declaringClass is the class containing the static field declaration for this key. * @param name is the name of static field declaration for this key. * @param defaultSchedulerClass is the default value of the option. Used when option is not set. * This class should implement {@link IScheduler#isDefaultScheduler()} to return true. * @throws OptionValidationException if {@code defaultSchedulerClass} does not have a public default * constructor. * @since 0.08 */ @SuppressWarnings("null") public SchedulerOptionKey(Class<?> declaringClass, String name, Class<? extends IScheduler> defaultSchedulerClass) { this(declaringClass, name, defaultSchedulerClass, null); } /** * Constructs a scheduler option key. * @param declaringClass is the class containing the static field declaration for this key. * @param name is the name of static field declaration for this key. * @param defaultSchedulerClass is the default value of the option. Used when option is not set. * This class should implement {@link IScheduler#isDefaultScheduler()} to return true. * @throws OptionValidationException if {@code defaultSchedulerClass} does not have a public default * constructor. * @since 0.08 */ public SchedulerOptionKey(Class<?> declaringClass, String name, Class<? extends IScheduler> defaultSchedulerClass, ScheduleValidatorOptionKey validatorKey) { super(declaringClass, name); _defaultSchedulerClass = defaultSchedulerClass; _validatorKey = validatorKey; validateClass(defaultSchedulerClass); assert(defaultValue().isDefaultScheduler()); } /*-------------------- * IOptionKey methods */ /** * {@inheritDoc} * <p> * This implementation supports conversion from strings and {@link IScheduler} class instances. * The string is used to look up the scheduler class from the current {@linkplain #getRegistry() registry}. */ @Override public IScheduler convertToValue(@Nullable Object value) { if (value instanceof String) { value = getRegistry().getClass((String)value); } if (value instanceof Class<?>) { value = SchedulerBase.instantiateClass(validateClass((Class<?>)value)); } return super.convertToValue(value); } /** * Returns newly constructed default instance. * <p> * Note that unlike most option keys, this will return a new instance everytime it is invoked! */ @Override public IScheduler defaultValue() { return SchedulerBase.instantiateClass(_defaultSchedulerClass); } @Override public void set(IOptionHolder holder, IScheduler value) { super.set(holder, value); } /** * Sets the option locally on the {@code holder} by instantiating a new instance of {@code schedulerClass}. * <p> * @param holder is the object on which the option will be set locally. * @param schedulerClass must either have a public no-argument constructor or must be an enum, in which * case the first enumerated value will be used. * @since 0.08 * @see #set(IOptionHolder, IScheduler) */ public void set(IOptionHolder holder, Class<? extends IScheduler> schedulerClass) { convertAndSet(holder, schedulerClass); } /** * Sets the option locally on the {@code holder} by instantiating a new instance of {@code schedulerClass}. * @param holder is the object on which the option will be set locally. * @param schedulerClass is a string that is used to lookup the scheduler class. It may either be a * fully qualified Java class name, or the simple class name listed in the {@linkplain #getRegistry() * scheduler registry.} * @since 0.08 * @see #set(IOptionHolder, Class) */ public void set(IOptionHolder holder, String schedulerClass) { convertAndSet(holder, schedulerClass); } @Override public Class<? extends IScheduler> type() { return IScheduler.class; } /** * {@inheritDoc} * <p> * Returns false if {@code scheduler} fails to {@linkplain IScheduler#validateForGraph(FactorGraph) validate} * graph containing {@code delegator}. */ @Override public boolean validForDelegator(IScheduler scheduler, IOptionHolder delegator) { if (delegator instanceof IDimpleEventSource) { IDimpleEventSource source = (IDimpleEventSource)delegator; FactorGraph graph = source.getContainingGraph(); if (graph != null) { try { scheduler.validateForGraph(graph); } catch (Exception ex) { return false; } } } return true; } @Override public IScheduler validate(IScheduler scheduler, @Nullable IOptionHolder optionHolder) { FactorGraph graph = optionHolder instanceof FactorGraph ? (FactorGraph)optionHolder : optionHolder instanceof ISolverFactorGraph ? ((ISolverFactorGraph)optionHolder).getModelObject() : null; if (graph != null) { try { scheduler.validateForGraph(graph); } catch (Exception ex) { throw new OptionValidationException("%s cannot be used with %s: %s", scheduler, graph, ex); } } return super.validate(scheduler, optionHolder); } /*---------------------------- * SchedulerOptionKey methods */ /** * The {@link Class} of the {@linkplain #defaultValue default scheduler value}. * <p> * Use this to check the default without instantiating an instance. * @since 0.08 */ public Class<? extends IScheduler> defaultClass() { return _defaultSchedulerClass; } /** * Returns {@linkplain DimpleEnvironment#schedulers() scheduler registry} for * {@linkplain DimpleEnvironment#active active environment}, which is used for * locating known scheduler classes by name. */ public ConstructorRegistry<IScheduler> getRegistry() { return DimpleEnvironment.active().schedulers(); } /** * The option key, if any, for looking up the validator to be used on schedules for this class of scheduler. * @since 0.08 */ public @Nullable ScheduleValidatorOptionKey getValidatorKey() { return _validatorKey; } /*------------------- * Protected methods */ protected Class<? extends IScheduler> validateClass(Class<?> schedulerClass) { try { return SchedulerBase.validateClass(schedulerClass); } catch (IllegalArgumentException ex) { throw new OptionValidationException("Not valid for option '%s': %s", this, ex.getMessage()); } } }