/*
* Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.yang.parser.spi.meta;
import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.EFFECTIVE_MODEL;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
/**
* Builder for effective model inference action. Model inference action is core principle of transforming
* declared model into effective model.
*
*
* Since YANG allows forward references, some inference actions need to be taken at a later point, where reference is
* actually resolved. Referenced objects are not retrieved directly but are represented as {@link Prerequisite}
* (prerequisite) for inference action to be taken.
*
*
* Some existing YANG statements are more complex and also object, for which effective model may be inferred is also
* represented as a {@link Prerequisite} which, when reference is available, will contain target context, which may be
* used for inference action.
*
*
Implementing inference action
* Effective inference action could always be splitted into two separate tasks:
*
* - Declaration of inference action and its prerequisites
* - Execution of inference action
*
*
*
* In order to declare inference action following steps needs
* to be taken:
*
* - Use {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)} to obtain
* {@link ModelActionBuilder}.
*
- Use builder to specify concrete prerequisites of inference action
* (other statements, values from identifier namespaces)
*
- Use builder to specify concrete set of nodes (or forward references to nodes)
* which will inference action mutate.
*
- Use {@link #apply(InferenceAction)} with {@link InferenceAction} implementation
* to register inference action.
*
*
*
* An action will be executed when:
*
* - {@link InferenceAction#apply(InferenceContext)} - all prerequisites (and declared forward references) are met,
* action could dereference them and start applying changes.
*
* - {@link InferenceAction#prerequisiteFailed(Collection)} - semantic parser finished all other satisfied
* inference actions and some of declared prerequisites was still not met.
*
*
*
*
* TODO: Insert real word example
*
*
Design notes
* {@link java.util.concurrent.Future} seems as viable and more standard alternative to {@link Prerequisite}, but
* Futures also carries promise that resolution of it is carried in other thread, which will actually put additional
* constraints on semantic parser.
*
*
* Also listening on multiple futures is costly, so we opted out of future and designed API, which later may introduce
* futures.
*/
public interface ModelActionBuilder {
interface InferenceContext {
}
@FunctionalInterface
interface Prerequisite {
/**
* Returns associated prerequisite once it is resolved.
*
* @param ctx Inference context in which the prerequisite was satisfied
* @return associated prerequisite once it is resolved.
*/
@NonNull T resolve(InferenceContext ctx);
}
/**
* User-defined inference action.
*/
interface InferenceAction {
/**
* Invoked once all prerequisites were met and forward references were resolved and inference action should be
* applied. Implementors may perform necessary changes to mutable objects which were declared.
*
* @throws InferenceException If inference action can not be processed. Note that this exception be used for
* user to debug YANG sources, so should provide helpful context to fix issue in sources.
*/
void apply(InferenceContext ctx);
/**
* Invoked once one of prerequisites was not met, even after all other satisfiable inference actions were
* processed.
*
*
* Implementors MUST throw {@link InferenceException} if semantic processing of model should be stopped
* and failed.
*
*
* List of failed prerequisites should be used to select right message / error type to debug problem in YANG
* sources.
*
* @param failed collection of prerequisites which were not met
* @throws InferenceException If inference action can not be processed. Note that this exception be used
* by user to debug YANG sources, hence it should provide helpful context to fix
* the issue in sources.
*/
void prerequisiteFailed(Collection extends Prerequisite>> failed);
/**
* Invoked once the prerequisite is deemed unavailable due to conformance reasons. This typically happens when
* a feature-dependent prerequisite does not have the appropriate feature activated.
*
*
* The default implementation invokes {@link #prerequisiteFailed(Collection)}, implementations should override
* this method if they wish, for example, to ignore the missing prerequisite.
*
* @param unavail Unavailable prerequisite
*/
@Beta
default void prerequisiteUnavailable(final Prerequisite> unavail) {
prerequisiteFailed(ImmutableList.of(unavail));
}
}
/**
* Action requires that the specified context transition to complete {@link ModelProcessingPhase#FULL_DECLARATION}
* phase and produce a declared statement.
*
* @param context Statement context which needs to complete the transition.
* @return A {@link Prerequisite} returning the declared statement of the requested context.
*/
> @NonNull Prerequisite requiresDeclared(StmtContext, ? extends D, ?> context);
/**
* Create a requirement on specified statement to be declared.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
, N extends StatementNamespace>
@NonNull Prerequisite requiresDeclared(StmtContext, ?, ?> context, Class namespace, K key);
/**
* Action requires that the specified context completes specified phase before {@link #apply(InferenceAction)}
* may be invoked.
*
* @param context Statement context which needs to complete the transition.
* @param phase ModelProcessingPhase which must have completed
* @return A {@link Prerequisite} returning the requested context.
*/
, E extends EffectiveStatement> @NonNull Prerequisite>
requiresCtx(StmtContext context, ModelProcessingPhase phase);
> @NonNull Prerequisite> requiresCtx(
StmtContext, ?, ?> context, Class<@NonNull N> namespace, K key, ModelProcessingPhase phase);
> @NonNull Prerequisite> requiresCtx(
StmtContext, ?, ?> context, Class<@NonNull N> namespace, NamespaceKeyCriterion criterion,
ModelProcessingPhase phase);
/**
* Action mutates the effective model of specified statement. This is a shorthand for
* {@code mutatesCtx(context, EFFECTIVE_MODEL}.
*
* @param context Target statement context
* @return A {@link Prerequisite} returning the requested context.
*/
default > @NonNull Prerequisite mutatesEffectiveCtx(final T context) {
return mutatesCtx(context, EFFECTIVE_MODEL);
}
, N extends ParserNamespace>>
@NonNull Prerequisite> mutatesEffectiveCtx(StmtContext, ?, ?> context, Class namespace,
K key);
, N extends ParserNamespace>>
@NonNull Prerequisite> mutatesEffectiveCtxPath(StmtContext, ?, ?> context,
Class namespace, Iterable keys);
/**
* Action mutates the specified statement in the specified phase. Target statement cannot complete specified
* phase before this action is applier.
*
* @param context Target statement context
* @return A {@link Prerequisite} returning the requested context.
*/
, T extends C> @NonNull Prerequisite mutatesCtx(T context,
ModelProcessingPhase phase);
/**
* Apply an {@link InferenceAction} when this action's prerequisites are resolved.
*
* @param action Inference action to apply
* @throws InferenceException if the action fails
* @throws NullPointerException if {@code action is null}
* @throws IllegalStateException if this action has an inference action already associated.
*/
void apply(InferenceAction action);
/**
* Create a requirement on specified statement context to be declared.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
, N extends StatementNamespace>
@NonNull Prerequisite> requiresDeclaredCtx(StmtContext, ?, ?> context,
Class namespace, K key);
/**
* Create a requirement on specified statement to become effective.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
> @NonNull Prerequisite requiresEffective(
StmtContext, ?, ? extends E> stmt);
/**
* Create a requirement on specified statement to become effective.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
, N extends StatementNamespace>
@NonNull Prerequisite requiresEffective(StmtContext, ?, ?> context, Class namespace, K key);
/**
* Create a requirement on specified statement context to become effective.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
, N extends StatementNamespace>
@NonNull Prerequisite> requiresEffectiveCtx(StmtContext, ?, ?> context,
Class namespace, K key);
/**
* Mark the fact that this action is mutating a namespace.
*
* @deprecated Undocumented method. Use at your own risk.
*/
@Deprecated
> @NonNull Prerequisite> mutatesNs(Mutable,?, ?> ctx,
Class namespace);
}