--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.SourceSpecificContext.PhaseCompletionProgress;
+
+class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBehaviour.Registry {
+
+ private static final List<ModelProcessingPhase> PHASE_EXECUTION_ORDER = ImmutableList.<ModelProcessingPhase>builder()
+ .add(ModelProcessingPhase.SourceLinkage)
+ .add(ModelProcessingPhase.StatementDefinition)
+ .add(ModelProcessingPhase.FullDeclaration)
+ .add(ModelProcessingPhase.EffectiveModel)
+ .build();
+
+ private final Map<QName,StatementDefinitionContext<?,?,?>> definitions = new HashMap<>();
+ private final Map<Class<?>,NamespaceBehaviourWithListeners<?, ?, ?>> namespaces = new HashMap<>();
+
+
+ private final Map<ModelProcessingPhase,StatementSupportBundle> supports;
+ private final Set<SourceSpecificContext> sources = new HashSet<>();
+
+ private ModelProcessingPhase currentPhase;
+ private ModelProcessingPhase finishedPhase;
+
+ public BuildGlobalContext(Map<ModelProcessingPhase, StatementSupportBundle> supports) {
+ super();
+ this.supports = supports;
+ }
+
+ public void addSource(@Nonnull StatementStreamSource source) {
+ sources.add(new SourceSpecificContext(this,source));
+ }
+
+ @Override
+ public StorageNodeType getStorageNodeType() {
+ return StorageNodeType.Global;
+ }
+
+ @Override
+ public NamespaceStorageNode getParentNamespaceStorage() {
+ return null;
+ }
+
+ @Override
+ public NamespaceBehaviour.Registry getBehaviourRegistry() {
+ return this;
+ }
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getNamespaceBehaviour(Class<N> type) {
+ NamespaceBehaviourWithListeners<?, ?, ?> potential = namespaces.get(type);
+ if (potential == null) {
+ NamespaceBehaviour<K, V, N> potentialRaw = supports.get(currentPhase).getNamespaceBehaviour(type);
+ if(potentialRaw != null) {
+ potential = new NamespaceBehaviourWithListeners<>(potentialRaw);
+ namespaces.put(type, potential);
+ }
+ }
+ if (potential != null) {
+ Preconditions.checkState(type.equals(potential.getIdentifier()));
+
+ /*
+ * Safe cast, previous checkState checks equivalence of key from
+ * which type argument are derived
+ */
+ @SuppressWarnings("unchecked")
+ NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K, V, N>) potential;
+ return casted;
+ }
+ throw new NamespaceNotAvailableException("Namespace " + type + "is not available in phase " + currentPhase);
+ }
+
+ public StatementDefinitionContext<?, ?, ?> getStatementDefinition(QName name) {
+ StatementDefinitionContext<?, ?, ?> potential = definitions.get(name);
+ if(potential == null) {
+ StatementSupport<?, ?, ?> potentialRaw = supports.get(currentPhase).getStatementDefinition(name);
+ if(potentialRaw != null) {
+ potential = new StatementDefinitionContext<>(potentialRaw);
+ definitions.put(name, potential);
+ }
+ }
+ return potential;
+ }
+
+ public EffectiveModelContext build() throws SourceException, ReactorException {
+ for(ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
+ startPhase(phase);
+ loadPhaseStatements();
+ completePhaseActions();
+ endPhase(phase);
+ }
+ return transform();
+ }
+
+ private EffectiveModelContext transform() {
+ Preconditions.checkState(finishedPhase == ModelProcessingPhase.EffectiveModel);
+ List<DeclaredStatement<?>> rootStatements = new ArrayList<>();
+ for(SourceSpecificContext source : sources) {
+ DeclaredStatement<?> root = source.getRoot().buildDeclared();
+ rootStatements.add(root);
+ }
+ return new EffectiveModelContext(rootStatements);
+ }
+
+ private void startPhase(ModelProcessingPhase phase) {
+ Preconditions.checkState(Objects.equals(finishedPhase, phase.getPreviousPhase()));
+ for(SourceSpecificContext source : sources) {
+ source.startPhase(phase);
+ }
+ currentPhase = phase;
+ }
+
+ private void loadPhaseStatements() throws SourceException {
+ Preconditions.checkState(currentPhase != null);
+ for(SourceSpecificContext source : sources) {
+ source.loadStatements();
+ }
+ }
+
+ private void completePhaseActions() throws ReactorException {
+ Preconditions.checkState(currentPhase != null);
+ ArrayList<SourceSpecificContext> sourcesToProgress = Lists.newArrayList(sources);
+ try {
+ boolean progressing = true;
+ while(progressing) {
+ // We reset progressing to false.
+ progressing = false;
+ Iterator<SourceSpecificContext> currentSource = sourcesToProgress.iterator();
+ while(currentSource.hasNext()) {
+ PhaseCompletionProgress sourceProgress = currentSource.next().tryToCompletePhase(currentPhase);
+ switch (sourceProgress) {
+ case FINISHED:
+ currentSource.remove();
+ case PROGRESS:
+ progressing = true;
+ case NO_PROGRESS:
+ // Noop;
+ }
+ }
+ }
+ } catch (SourceException e) {
+ throw Throwables.propagate(e);
+ }
+ if(!sourcesToProgress.isEmpty()) {
+ SomeModifiersUnresolvedException buildFailure = new SomeModifiersUnresolvedException(currentPhase);
+ for(SourceSpecificContext failedSource : sourcesToProgress) {
+ SourceException sourceEx = failedSource.failModifiers(currentPhase);
+ buildFailure.addSuppressed(sourceEx);
+ }
+ throw buildFailure;
+ }
+ }
+
+ private void endPhase(ModelProcessingPhase phase) {
+ Preconditions.checkState(currentPhase == phase);
+ finishedPhase = currentPhase;
+ }
+
+ public Set<SourceSpecificContext> getSources() {
+ return sources;
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.EnumMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+
+public class CrossSourceStatementReactor {
+
+ private final Map<ModelProcessingPhase,StatementSupportBundle> supportedTerminology;
+
+ CrossSourceStatementReactor(Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology) {
+ this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
+ }
+
+ public static final Builder builder() {
+ return new Builder();
+ }
+
+ public final BuildAction newBuild() {
+ return new BuildAction();
+ }
+
+ public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor>{
+
+ final Map<ModelProcessingPhase,StatementSupportBundle> bundles = new EnumMap<>(ModelProcessingPhase.class);
+
+ public Builder setBundle(ModelProcessingPhase phase,StatementSupportBundle bundle) {
+ bundles.put(phase, bundle);
+ return this;
+ }
+
+ @Override
+ public CrossSourceStatementReactor build() {
+ return new CrossSourceStatementReactor(bundles);
+ }
+
+ }
+
+ public class BuildAction {
+
+ private final BuildGlobalContext context;
+
+ public BuildAction() {
+ this.context = new BuildGlobalContext(supportedTerminology);
+ }
+
+ public void addSource(StatementStreamSource source) {
+ context.addSource(source);
+ }
+
+ public EffectiveModelContext build() throws SourceException, ReactorException {
+ return context.build();
+ }
+
+
+
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+
+public class EffectiveModelContext implements Immutable {
+
+ private final ImmutableList<DeclaredStatement<?>> rootStatements;
+
+ public EffectiveModelContext(List<DeclaredStatement<?>> rootStatements) {
+ this.rootStatements = ImmutableList.copyOf(rootStatements);
+ }
+
+ public ImmutableList<DeclaredStatement<?>> getRootStatements() {
+ return rootStatements;
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.EffectiveModel;
+import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.FullDeclaration;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextMutation;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnNamespaceItemAdded;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnPhaseFinished;
+
+class ModifierImpl implements ModelActionBuilder {
+
+ private final ModelProcessingPhase phase;
+ private final Set<AbstractPrerequisite<?>> unsatisfied = new HashSet<>();
+ private final Set<AbstractPrerequisite<?>> mutations = new HashSet<>();
+
+ private InferenceAction action;
+ private boolean actionApplied = false;
+
+ ModifierImpl(ModelProcessingPhase phase) {
+ this.phase = Preconditions.checkNotNull(phase);
+ }
+
+ private <D> AbstractPrerequisite<D> addReq(AbstractPrerequisite<D> prereq) {
+ unsatisfied.add(prereq);
+ return prereq;
+ }
+
+ private <T> AbstractPrerequisite<T> addMutation(AbstractPrerequisite<T> mutation) {
+ mutations.add(mutation);
+ return mutation;
+ }
+
+
+
+ private void checkNotRegistered() {
+ Preconditions.checkState(action == null, "Action was already registered.");
+ }
+
+ private IllegalStateException shouldNotHappenProbablyBug(SourceException e) {
+ return new IllegalStateException("Source exception during registering prerequisite. This is probably bug.",e);
+ }
+
+ private void tryToResolve() throws InferenceException {
+ if(action == null) {
+ return; // Action was not yet defined
+ }
+ if(removeSatisfied()) {
+ applyAction();
+ }
+ }
+
+ private boolean removeSatisfied() {
+ Iterator<AbstractPrerequisite<?>> prereq = unsatisfied.iterator();
+ boolean allSatisfied = true;
+ while(prereq.hasNext()) {
+ if(prereq.next().isDone()) {
+ prereq.remove(); // We are removing current prerequisite from list.
+ } else {
+ allSatisfied = false;
+ }
+ }
+ return allSatisfied;
+ }
+
+ ModelProcessingPhase getPhase() {
+ return phase;
+ }
+
+ boolean isApplied() {
+
+ return actionApplied;
+ }
+
+ void failModifier() throws InferenceException {
+ removeSatisfied();
+ action.prerequisiteFailed(unsatisfied);
+ action = null;
+ }
+
+ private void applyAction() throws InferenceException {
+
+ action.apply();
+ //Â Mark all mutations as performed, so context node could move to next.
+ actionApplied = true;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private <K, C extends StmtContext<?,?,?>, N extends StatementNamespace<K, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(StmtContext<?, ?, ?> context, Class<N> namespace, K key,ModelProcessingPhase phase) {
+ checkNotRegistered();
+ try {
+ AddedToNamespace<C> addedToNs = new AddedToNamespace<C>(phase);
+ addReq(addedToNs);
+ contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,addedToNs);
+ return addedToNs;
+ } catch (SourceException e) {
+ throw shouldNotHappenProbablyBug(e);
+ }
+ }
+
+ private <C extends StmtContext<?, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(C context, ModelProcessingPhase phase) {
+ Preconditions.checkState(action == null, "Action was already registered.");
+ try {
+ PhaseFinished<C> phaseFin = new PhaseFinished<C>();
+ addReq(phaseFin);
+ contextImpl(context).addPhaseCompletedListener(FullDeclaration,phaseFin);
+ return phaseFin;
+ } catch (SourceException e) {
+ throw shouldNotHappenProbablyBug(e);
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private <K, C extends StmtContext.Mutable<?, ?, ?> , N extends StatementNamespace<K, ?, ? >> AbstractPrerequisite<C> mutatesCtxImpl(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
+ try {
+ PhaseModificationInNamespace<C> mod = new PhaseModificationInNamespace<C>(phase);
+ addMutation(mod);
+ contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,mod);
+ return mod;
+ } catch (SourceException e) {
+ throw shouldNotHappenProbablyBug(e);
+ }
+ }
+
+ private static StatementContextBase<?,?,?> contextImpl(StmtContext<?,?,?> context) {
+ Preconditions.checkArgument(context instanceof StatementContextBase,"Supplied context was not provided by this reactor.");
+ return StatementContextBase.class.cast(context);
+ }
+
+ @Override
+ public <C extends Mutable<?, ?, ?>, CT extends C> Prerequisite<C> mutatesCtx(CT context, ModelProcessingPhase phase) {
+ try {
+ return addMutation(new PhaseMutation<C>(contextImpl(context),phase));
+ } catch (InferenceException e) {
+ throw shouldNotHappenProbablyBug(e);
+ }
+ }
+
+ @Override
+ public <A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> AbstractPrerequisite<StmtContext<A, D, E>> requiresCtx(StmtContext<A, D, E> context, ModelProcessingPhase phase) {
+ return requiresCtxImpl(context, phase);
+ }
+
+
+ @Override
+ public <K, N extends StatementNamespace<K, ?, ? >> Prerequisite<StmtContext<?,?,?>> requiresCtx(StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
+ return requiresCtxImpl(context, namespace, key, phase);
+ }
+
+ @Override
+ public <D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(StmtContext<?, ? extends D, ?> context) {
+ return requiresCtxImpl(context,FullDeclaration).transform(StmtContextUtils.<D>buildDeclared());
+ }
+
+ @Override
+ public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> AbstractPrerequisite<StmtContext<?, D, ?>> requiresDeclaredCtx(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+ return requiresCtxImpl(context, namespace, key,FullDeclaration);
+ }
+
+ @Override
+ public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<D> requiresDeclared(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+ final AbstractPrerequisite<StmtContext<?,D,?>> rawContext = requiresCtxImpl(context, namespace, key,FullDeclaration);
+ return rawContext.transform(StmtContextUtils.<D>buildDeclared());
+ }
+
+ @Override
+ public <E extends EffectiveStatement<?, ?>> Prerequisite<E> requiresEffective(StmtContext<?, ?, ? extends E> stmt) {
+ return requiresCtxImpl(stmt,EffectiveModel).transform(StmtContextUtils.<E>buildEffective());
+ }
+
+ @Override
+ public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<StmtContext<?, ?, E>> requiresEffectiveCtx(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+ return requiresCtxImpl(contextImpl(context),namespace,key,EffectiveModel);
+ }
+
+ @Override
+ public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<E> requiresEffective(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+ final AbstractPrerequisite<StmtContext<?,?,E>> rawContext = requiresCtxImpl(context, namespace, key,EffectiveModel);
+ return rawContext.transform(StmtContextUtils.<E>buildEffective());
+ }
+
+
+ @Override
+ public <N extends IdentifierNamespace<?, ?>> Prerequisite<Mutable<?, ?, ?>> mutatesNs(Mutable<?, ?, ?> context,
+ Class<N> namespace) {
+ try {
+ return addMutation(new NamespaceMutation<N>(contextImpl(context),namespace));
+ } catch (SourceException e) {
+ throw shouldNotHappenProbablyBug(e);
+ }
+ }
+
+ @Override
+ public <T extends Mutable<?, ?, ?>> Prerequisite<T> mutatesEffectiveCtx(T stmt) {
+ return mutatesCtx(stmt, EffectiveModel);
+ }
+
+
+ @Override
+ public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtx(
+ StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+ return mutatesCtxImpl(context, namespace, key, EffectiveModel);
+ }
+
+
+
+ @Override
+ public void apply(InferenceAction action) throws InferenceException {
+ this.action = Preconditions.checkNotNull(action);
+ tryToResolve();
+ }
+
+ private abstract class AbstractPrerequisite<T> implements Prerequisite<T> {
+
+ private T value;
+ private boolean done = false;
+
+ @Override
+ public T get() {
+ Preconditions.checkState(isDone());
+ return value;
+ }
+
+ @Override
+ public boolean isDone() {
+ return done;
+ }
+
+ protected void resolvePrereq(T value) throws InferenceException {
+ Preconditions.checkState(!isDone());
+ this.value = value;
+ this.done = true;
+ tryToResolve();
+ }
+
+ protected <O> Prerequisite<O> transform(final Function<? super T,O> transformation) {
+
+ return new Prerequisite<O>() {
+
+ @Override
+ public O get() {
+ return transformation.apply(AbstractPrerequisite.this.get());
+ }
+
+ @Override
+ public boolean isDone() {
+ return AbstractPrerequisite.this.isDone();
+ }
+
+ };
+ }
+
+ }
+
+ private class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
+
+ @SuppressWarnings("unchecked")
+ public PhaseMutation(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws InferenceException {
+ context.addMutation(phase, this);
+ resolvePrereq((C) context);
+ }
+
+ @Override
+ public boolean isFinished() {
+ return isApplied();
+ }
+
+
+ }
+ private class PhaseFinished<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C> implements OnPhaseFinished {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
+ resolvePrereq((C) (context));
+ }
+ }
+
+ private class NamespaceMutation<N extends IdentifierNamespace<?,?>> extends AbstractPrerequisite<StmtContext.Mutable<?, ?, ?>> {
+
+ public NamespaceMutation(StatementContextBase<?, ?, ?> ctx, Class<N> namespace) throws InferenceException {
+ resolvePrereq(ctx);
+ }
+
+ }
+
+ private class AddedToNamespace<C extends StmtContext<?,?,?>> extends AbstractPrerequisite<C> implements OnNamespaceItemAdded,OnPhaseFinished {
+
+ private final ModelProcessingPhase phase;
+
+ public <K, N extends StatementNamespace<K, ?, ?>> AddedToNamespace(ModelProcessingPhase phase) {
+ this.phase = phase;
+ }
+
+ @Override
+ public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
+ Object value) throws SourceException {
+ StatementContextBase<?, ?, ?> targetContext = (StatementContextBase<?, ?, ?>) value;
+ targetContext.addPhaseCompletedListener(phase, this);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
+ resolvePrereq((C) context);
+ }
+
+ }
+
+ private class PhaseModificationInNamespace<C extends Mutable<?,?,?>> extends AbstractPrerequisite<C> implements OnNamespaceItemAdded, ContextMutation {
+
+ private final ModelProcessingPhase modPhase;
+
+ public <K, N extends StatementNamespace<K, ?, ?>> PhaseModificationInNamespace(ModelProcessingPhase phase) throws SourceException {
+ Preconditions.checkArgument(phase != null, "Model processing phase must not be null");
+ this.modPhase = phase;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
+ Object value) throws SourceException {
+ context.addMutation(modPhase,this);
+ resolvePrereq((C) context);
+ }
+
+ @Override
+ public boolean isFinished() {
+ return isApplied();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Iterator;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+
+final class NamespaceBehaviourWithListeners<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+
+ static abstract class ValueAddedListener {
+
+ private org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode ctxNode;
+
+ public ValueAddedListener(NamespaceStorageNode contextNode) {
+ this.ctxNode = contextNode;
+ }
+
+ abstract void onValueAdded(Object key, Object value);
+
+ }
+
+ private final NamespaceBehaviour<K, V, N> delegate;
+ private final Multimap<K, ValueAddedListener> listeners = HashMultimap.create();
+
+ protected NamespaceBehaviourWithListeners(NamespaceBehaviour<K, V, N> delegate) {
+ super(delegate.getIdentifier());
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void addTo(NamespaceBehaviour.NamespaceStorageNode storage,
+ K key, V value) {
+ delegate.addTo(storage, key, value);
+
+ Iterator<ValueAddedListener> keyListeners = listeners.get(key).iterator();
+ while(keyListeners.hasNext()) {
+ ValueAddedListener listener = keyListeners.next();
+ if(listener.ctxNode == storage || hasIdentiticalValue(listener.ctxNode,key,value)) {
+ keyListeners.remove();
+ listener.onValueAdded(key, value);
+ }
+ }
+ }
+
+ private boolean hasIdentiticalValue(NamespaceBehaviour.NamespaceStorageNode ctxNode, K key, V value) {
+ return getFrom(ctxNode, key) == value;
+ }
+
+ void addValueListener(K key, ValueAddedListener listener) {
+ listeners.put(key, listener);
+ }
+
+ @Override
+ public V getFrom(NamespaceBehaviour.NamespaceStorageNode storage,
+ K key) {
+ return delegate.getFrom(storage, key);
+ }
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+abstract class NamespaceStorageSupport implements NamespaceStorageNode {
+
+ private final Map<Class<?>,Map<?,?>> namespaces = new HashMap<>();
+
+
+ @Override
+ public abstract NamespaceStorageNode getParentNamespaceStorage();
+
+ public abstract NamespaceBehaviour.Registry getBehaviourRegistry();
+
+ protected void checkLocalNamespaceAllowed(Class<? extends IdentifierNamespace<?, ?>> type) {
+ // NOOP
+ }
+
+ protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(Class<N> type, K key, V value) {
+ // NOOP
+ }
+
+ public final <K, VT, V extends VT ,N extends IdentifierNamespace<K, V>> VT getFromNamespace(Class<N> type, K key)
+ throws NamespaceNotAvailableException {
+ return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this,key);
+ }
+
+ public final <K,V,VT extends V,N extends IdentifierNamespace<K, V>> void addToNs(Class<N> type, K key, VT value)
+ throws NamespaceNotAvailableException {
+ getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this,key,value);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public final <K, N extends StatementNamespace<K, ?,?>> void addContextToNamespace(Class<N> type, K key, StmtContext<?, ?, ?> value)
+ throws NamespaceNotAvailableException {
+ getBehaviourRegistry().getNamespaceBehaviour((Class)type).addTo(this, key, value);
+ }
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key) {
+ @SuppressWarnings("unchecked")
+ Map<K, V> localNamespace = (Map<K,V>) namespaces.get(type);
+ if(localNamespace != null) {
+ return localNamespace.get(key);
+ }
+ return null;
+ }
+
+
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value) {
+ @SuppressWarnings("unchecked")
+ Map<K, V> localNamespace = (Map<K,V>) namespaces.get(type);
+ if(localNamespace == null) {
+ checkLocalNamespaceAllowed(type);
+ localNamespace = new HashMap<>();
+ namespaces.put(type, localNamespace);
+ }
+ localNamespace.put(key,value);
+ onNamespaceElementAdded(type,key,value);
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+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.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+
+class RootStatementContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+ extends StatementContextBase<A, D,E> {
+
+
+ private final SourceSpecificContext sourceContext;
+
+ RootStatementContext(ContextBuilder<A, D,E> builder, SourceSpecificContext sourceContext) throws SourceException {
+ super(builder);
+ this.sourceContext = sourceContext;
+ }
+
+ @Override
+ public StatementContextBase<?,?, ?> getParentContext() {
+ return null;
+ }
+
+ @Override
+ public NamespaceStorageNode getParentNamespaceStorage() {
+ return sourceContext;
+ }
+
+ @Override
+ public Registry getBehaviourRegistry() {
+ return sourceContext;
+ }
+
+ @Override
+ public RootStatementContext<?,?,?> getRoot() {
+ return this;
+ }
+
+ SourceSpecificContext getSourceContext() {
+ return sourceContext;
+ }
+
+
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ImportedNamespaceContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextBuilder;
+
+public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable {
+
+ public enum PhaseCompletionProgress {
+ NO_PROGRESS,
+ PROGRESS,
+ FINISHED
+ }
+
+ private final StatementStreamSource source;
+ private final BuildGlobalContext currentContext;
+ private final Collection<NamespaceStorageNode> importedNamespaces = new ArrayList<>();
+ private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
+
+ private RootStatementContext<?,?, ?> root;
+
+ private ModelProcessingPhase inProgressPhase;
+ private ModelProcessingPhase finishedPhase;
+
+
+ SourceSpecificContext(BuildGlobalContext currentContext,StatementStreamSource source) {
+ this.source = source;
+ this.currentContext = currentContext;
+ }
+
+ StatementDefinitionContext<?,?,?> getDefinition(QName name) {
+ return currentContext.getStatementDefinition(name);
+ }
+
+ ContextBuilder<?, ?, ?> createDeclaredChild(StatementContextBase<?, ?, ?> current, QName name, StatementSourceReference ref) {
+ StatementDefinitionContext<?,?,?> def = getDefinition(name);
+ Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.",name);
+ if(current == null) {
+ return createDeclaredRoot(def,ref);
+ }
+ return current.substatementBuilder(def,ref);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private ContextBuilder<?,?, ?> createDeclaredRoot(StatementDefinitionContext<?,?,?> def, StatementSourceReference ref) {
+ return new ContextBuilder(def,ref) {
+
+ @Override
+ public StatementContextBase build() throws SourceException {
+ if(root == null) {
+ root = new RootStatementContext(this, SourceSpecificContext.this);
+ } else {
+ Preconditions.checkState(root.getIdentifier().equals(getIdentifier()), "Root statement was already defined.");
+ }
+ root.resetLists();
+ return root;
+ }
+
+ };
+ }
+
+ RootStatementContext<?,?,?> getRoot() {
+ return root;
+ }
+
+ DeclaredStatement<?> buildDeclared() {
+ return root.buildDeclared();
+ }
+
+ EffectiveStatement<?,?> build() {
+ return root.buildEffective();
+ }
+
+ void startPhase(ModelProcessingPhase phase) {
+ @Nullable ModelProcessingPhase previousPhase = phase.getPreviousPhase();
+ Preconditions.checkState(Objects.equals(previousPhase, finishedPhase));
+ Preconditions.checkState(modifiers.get(previousPhase).isEmpty());
+ inProgressPhase = phase;
+ }
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value) {
+ if(ImportedNamespaceContext.class.isAssignableFrom(type)) {
+ importedNamespaces.add((NamespaceStorageNode) value);
+ }
+ getRoot().addToLocalStorage(type, key, value);
+ }
+
+ @Override
+ public StorageNodeType getStorageNodeType() {
+ return StorageNodeType.SourceLocalSpecial;
+ }
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key) {
+ final V potentialLocal = getRoot().getFromLocalStorage(type, key);
+ if(potentialLocal != null) {
+ return potentialLocal;
+ }
+ for(NamespaceStorageNode importedSource : importedNamespaces) {
+ V potential = importedSource.getFromLocalStorage(type, key);
+ if(potential != null) {
+ return potential;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type) {
+ return currentContext.getNamespaceBehaviour(type);
+ }
+
+ @Override
+ public NamespaceStorageNode getParentNamespaceStorage() {
+ return currentContext;
+ }
+
+ PhaseCompletionProgress tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
+ Collection<ModifierImpl> currentPhaseModifiers = modifiers.get(phase);
+ Iterator<ModifierImpl> modifier = currentPhaseModifiers.iterator();
+ boolean hasProgressed = false;
+ while(modifier.hasNext()) {
+ if(modifier.next().isApplied()) {
+ modifier.remove();
+ hasProgressed = true;
+ }
+ }
+ if(root.tryToCompletePhase(phase) && currentPhaseModifiers.isEmpty()) {
+ finishedPhase = phase;
+ return PhaseCompletionProgress.FINISHED;
+
+ }
+ if(hasProgressed) {
+ return PhaseCompletionProgress.PROGRESS;
+ }
+ return PhaseCompletionProgress.NO_PROGRESS;
+ }
+
+ ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
+ ModifierImpl action = new ModifierImpl(phase);
+ modifiers.put(phase, action);
+ return action;
+ }
+
+ @Override
+ public String toString() {
+ return "SourceSpecificContext [source=" + source + ", current=" + inProgressPhase + ", finished="
+ + finishedPhase + "]";
+ }
+
+ SourceException failModifiers(ModelProcessingPhase identifier) {
+ InferenceException sourceEx = new InferenceException("Fail to infer source relationships", root.getStatementSourceReference());
+
+
+ for(ModifierImpl mod : modifiers.get(identifier)) {
+ try {
+ mod.failModifier();
+ } catch (SourceException e) {
+ sourceEx.addSuppressed(e);
+ }
+ }
+ return sourceEx;
+ }
+
+ void loadStatements() throws SourceException {
+ switch (inProgressPhase) {
+ case SourceLinkage:
+ source.writeLinkage(new StatementContextWriter(this, inProgressPhase),stmtDef());
+ break;
+ case StatementDefinition:
+ source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
+ case FullDeclaration:
+ source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
+
+ default:
+ break;
+ }
+ }
+
+ private PrefixToModule prefixes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private QNameToStatementDefinition stmtDef() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.ValueAddedListener;
+
+abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends
+ NamespaceStorageSupport implements StmtContext.Mutable<A, D, E>, Identifiable<StatementIdentifier> {
+
+ interface OnNamespaceItemAdded extends EventListener{
+
+ void namespaceItemAdded(StatementContextBase<?,?,?> context, Class<?> namespace, Object key, Object value) throws SourceException;
+
+ }
+
+ interface OnPhaseFinished extends EventListener{
+
+ void phaseFinished(StatementContextBase<?,?,?> context, ModelProcessingPhase phase) throws SourceException;
+
+ }
+
+ interface ContextMutation {
+
+ boolean isFinished();
+
+ }
+
+ abstract static class ContextBuilder<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
+
+ private final StatementDefinitionContext<A, D, E> definition;
+ private final StatementSourceReference stmtRef;
+ private String rawArg;
+ private StatementSourceReference argRef;
+
+ public ContextBuilder(StatementDefinitionContext<A, D, E> def, StatementSourceReference sourceRef) {
+ this.definition = def;
+ this.stmtRef = sourceRef;
+ }
+
+ public void setArgument(@Nonnull String argument, @Nonnull StatementSourceReference argumentSource) {
+ Preconditions.checkArgument(definition.hasArgument(), "Statement does not take argument.");
+ this.rawArg = Preconditions.checkNotNull(argument);
+ this.argRef = Preconditions.checkNotNull(argumentSource);
+ }
+
+ public String getRawArgument() {
+ return rawArg;
+ }
+
+ public StatementSourceReference getStamementSource() {
+ return stmtRef;
+ }
+
+ public StatementSourceReference getArgumentSource() {
+ return argRef;
+ }
+
+ public StatementDefinitionContext<A, D, E> getDefinition() {
+ return definition;
+ }
+
+ public StatementIdentifier getIdentifier() {
+ return new StatementIdentifier(definition.getStatementName(), rawArg);
+ }
+
+ public abstract StatementContextBase<A, D, E> build() throws SourceException;
+
+ }
+
+ private final StatementDefinitionContext<A, D, E> definition;
+ private final StatementIdentifier identifier;
+ private final StatementSourceReference statementDeclSource;
+ private final A argument;
+
+ private LinkedHashMap<StatementIdentifier, StatementContextBase<?, ?, ?> > substatements = new LinkedHashMap<>();
+
+ private Collection<StatementContextBase<?, ?, ?>> declared = new ArrayList<>();
+ private Collection<StatementContextBase<?, ?, ?>> effective = new ArrayList<>();
+
+ private ModelProcessingPhase completedPhase;
+
+ private Multimap<ModelProcessingPhase,OnPhaseFinished> phaseListeners = HashMultimap.create();
+ private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = HashMultimap.create();
+
+ private D declaredInstance;
+ private E effectiveInstance;
+
+
+ StatementContextBase(@Nonnull ContextBuilder<A, D, E> builder) throws SourceException {
+ this.definition = builder.getDefinition();
+ this.identifier = builder.getIdentifier();
+ this.statementDeclSource = builder.getStamementSource();
+ this.argument = definition.parseArgumentValue(this, this.rawStatementArgument());
+ this.completedPhase = null;
+ }
+
+ @Override
+ public abstract StatementContextBase<?, ?, ?> getParentContext();
+
+ @Override
+ public abstract RootStatementContext<?, ?, ?> getRoot();
+
+
+ @Override
+ public StatementIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public StatementSource getStatementSource() {
+ return statementDeclSource.getStatementSource();
+ }
+
+ @Override
+ public StatementSourceReference getStatementSourceReference() {
+ return statementDeclSource;
+ }
+
+ @Override
+ public String rawStatementArgument() {
+ return identifier.getArgument();
+ }
+
+ @Override
+ public A getStatementArgument() {
+ return argument;
+ }
+
+ @Override
+ public Collection<? extends StmtContext<?, ?, ?>> declaredSubstatements() {
+ return Collections.unmodifiableCollection(declared);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public ContextBuilder<?, ?, ?> substatementBuilder(StatementDefinitionContext<?, ?, ?> def,
+ StatementSourceReference ref) {
+ return new ContextBuilder(def, ref) {
+
+ @Override
+ public StatementContextBase build() throws SourceException {
+ StatementContextBase<?, ?, ?> potential = substatements.get(getIdentifier());
+ if(potential == null) {
+ potential = new SubstatementContext(StatementContextBase.this, this);
+ substatements.put(getIdentifier(), potential);
+ }
+ potential.resetLists();
+ switch (this.getStamementSource().getStatementSource()) {
+ case DECLARATION:
+ declared.add(potential);
+ break;
+ case CONTEXT:
+ effective.add(potential);
+ break;
+ }
+ return potential;
+ }
+ };
+ }
+
+ @Override
+ public StorageNodeType getStorageNodeType() {
+ return StorageNodeType.StatementLocal;
+ }
+
+ @Override
+ public D buildDeclared() {
+ Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FullDeclaration || completedPhase == ModelProcessingPhase.EffectiveModel);
+ if (declaredInstance == null) {
+ declaredInstance = definition().getFactory().createDeclared(this);
+ }
+ return declaredInstance;
+ }
+
+ @Override
+ public E buildEffective() {
+ Preconditions.checkArgument(completedPhase == ModelProcessingPhase.EffectiveModel);
+ if (effectiveInstance == null) {
+ effectiveInstance = definition().getFactory().createEffective(this);
+ }
+ return effectiveInstance;
+ }
+
+
+ void resetLists() {
+ declared.clear();
+ }
+
+ boolean tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
+ if(phase.equals(completedPhase)) {
+ return true;
+ }
+ Iterator<ContextMutation> openMutations = phaseMutation.get(phase).iterator();
+ boolean finished = true;
+ while(openMutations.hasNext()) {
+ ContextMutation current = openMutations.next();
+ if(current.isFinished()) {
+ openMutations.remove();
+ } else {
+ finished = false;
+ }
+ }
+ for(StatementContextBase<?, ?, ?> child: declared) {
+ finished &= child.tryToCompletePhase(phase);
+ }
+ if(finished) {
+ onPhaseCompleted(phase);
+ return true;
+ }
+ return false;
+ }
+
+
+ private void onPhaseCompleted(ModelProcessingPhase phase) throws SourceException {
+ completedPhase = phase;
+ Iterator<OnPhaseFinished> listener = phaseListeners.get(completedPhase).iterator();
+ while(listener.hasNext()) {
+ listener.next().phaseFinished(this, phase);
+ listener.remove();
+ }
+ }
+
+ /**
+ *
+ * Ends declared section of current node.
+ *
+ * @param ref
+ * @throws SourceException
+ *
+ */
+ void endDeclared(StatementSourceReference ref,ModelProcessingPhase phase) throws SourceException {
+ definition().onDeclarationFinished(this,phase);
+ }
+
+ protected final StatementDefinitionContext<A, D, E> definition() {
+ return definition;
+ }
+
+ @Override
+ protected void checkLocalNamespaceAllowed(Class<? extends IdentifierNamespace<?, ?>> type) {
+ definition().checkNamespaceAllowed(type);
+ }
+
+ @Override
+ protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(Class<N> type, K key, V value) {
+ //definition().onNamespaceElementAdded(this, type, key, value);
+ }
+
+ <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, K key, final OnNamespaceItemAdded listener) throws SourceException {
+ Object potential = getFromNamespace(type, key);
+ if(potential != null) {
+ listener.namespaceItemAdded(this, type, key, potential);
+ return;
+ }
+ NamespaceBehaviour<K,V,N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
+ if(behaviour instanceof NamespaceBehaviourWithListeners) {
+ NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K,V,N>) behaviour;
+ casted.addValueListener(key, new ValueAddedListener(this) {
+ @Override
+ void onValueAdded(Object key, Object value) {
+ try {
+ listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
+ } catch (SourceException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public StatementDefinition getPublicDefinition() {
+ return definition().getPublicView();
+ }
+
+ @Override
+ public ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
+ return getRoot().getSourceContext().newInferenceAction(phase);
+ }
+
+ void addPhaseCompletedListener(ModelProcessingPhase phase, OnPhaseFinished listener) throws SourceException {
+ ModelProcessingPhase finishedPhase = completedPhase;
+ while (finishedPhase != null) {
+ if(phase.equals(finishedPhase)) {
+ listener.phaseFinished(this, finishedPhase);
+ return;
+ }
+ finishedPhase = finishedPhase.getPreviousPhase();
+ }
+ phaseListeners.put(phase, listener);
+ }
+
+ void addMutation(ModelProcessingPhase phase, ContextMutation mutation) {
+ ModelProcessingPhase finishedPhase = completedPhase;
+ while (finishedPhase != null) {
+ if(phase.equals(finishedPhase)) {
+ throw new IllegalStateException("Mutation registered after phase was completed.");
+ }
+ finishedPhase = finishedPhase.getPreviousPhase();
+ }
+ phaseMutation.put(phase, mutation);
+ }
+
+ @Override
+ public <K,KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(
+ Class<N> namepsace, KT key, StmtContext<?, ?, ?> stmt) {
+ addContextToNamespace(namepsace,(K) key, stmt);
+ }
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextBuilder;
+
+class StatementContextWriter implements StatementWriter {
+
+ private final SourceSpecificContext ctx;
+ private StatementContextBase<?, ?, ?> parent;
+ private ContextBuilder<?, ?, ?> current;
+ private ModelProcessingPhase phase;
+
+ public StatementContextWriter(SourceSpecificContext ctx, ModelProcessingPhase phase) {
+ this.ctx = Preconditions.checkNotNull(ctx);
+ this.phase = Preconditions.checkNotNull(phase);
+ }
+
+ @Override
+ public void startStatement(QName name, StatementSourceReference ref) throws SourceException {
+ defferedCreate();
+ current = ctx.createDeclaredChild(parent, name, ref);
+
+ }
+
+ @Override
+ public void argumentValue(String value, StatementSourceReference ref) {
+ Preconditions.checkState(current != null, "Could not two arguments for one statement.");
+ current.setArgument(value, ref);
+ }
+
+ void defferedCreate() throws SourceException {
+ if(current != null) {
+ parent = current.build();
+ current = null;
+ }
+ }
+
+ @Override
+ public void endStatement(StatementSourceReference ref) throws SourceException {
+ defferedCreate();
+ Preconditions.checkState(parent != null);
+ parent.endDeclared(ref,phase);
+ parent = parent.getParentContext();
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+class StatementDefinitionContext<A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A,D>> {
+ private final StatementSupport<A,D,E> support;
+ public StatementDefinitionContext(StatementSupport<A,D,E> support) {
+ this.support= support;
+ }
+
+
+ public StatementFactory<A,D,E> getFactory() {
+ return support;
+ }
+
+ public A parseArgumentValue(StmtContext<A,D,E> context, String value) throws SourceException {
+ return support.parseArgumentValue(context,value);
+ }
+
+
+ public void checkNamespaceAllowed(Class<? extends IdentifierNamespace<?,?>> namespace) throws NamespaceNotAvailableException {
+ // Noop
+ }
+
+ public StatementDefinition getPublicView() {
+ return support.getPublicView();
+ }
+
+ public boolean onStatementAdded(Mutable<A,D,E> stmt) {
+ return false;
+ }
+
+
+ public void onDeclarationFinished(Mutable<A,D,E> statement, ModelProcessingPhase phase) throws SourceException {
+ switch (phase) {
+ case SourceLinkage:
+ support.onLinkageDeclared(statement);
+ break;
+ case StatementDefinition:
+ support.onStatementDefinitionDeclared(statement);
+ case FullDeclaration:
+ support.onFullDefinitionDeclared(statement);
+ default:
+ break;
+ }
+ }
+
+
+
+ public Class<?> getRepresentingClass() {
+ return support.getDeclaredRepresentationClass();
+ }
+
+
+ public boolean hasArgument() {
+ return support.getArgumentName() != null;
+ }
+
+
+ public QName getStatementName() {
+ return support.getStatementName();
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+class StatementIdentifier {
+
+ private final @Nonnull QName name;
+ private final @Nullable String argument;
+
+ StatementIdentifier(QName name, String argument) {
+ this.name = Preconditions.checkNotNull(name);
+ this.argument = argument;
+ }
+
+ QName getName() {
+ return name;
+ }
+
+ String getArgument() {
+ return argument;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + name.hashCode();
+ result = prime * result + ((argument == null) ? 0 : argument.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ StatementIdentifier other = (StatementIdentifier) obj;
+ if (!name.equals(other.name)) {
+ return false;
+ }
+ if (!Objects.equal(argument, other.argument)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "StatementIdentifier [name=" + name + ", argument=" + argument + "]";
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+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.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+class SubstatementContext<A,D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+ extends StatementContextBase<A,D,E> {
+
+ private final StatementContextBase<?,?,?> parent;
+
+ SubstatementContext(StatementContextBase<?,?,?> parent,ContextBuilder<A,D,E> builder) throws SourceException {
+ super(builder);
+ this.parent = Preconditions.checkNotNull(parent, "Parent must not be null");
+ }
+
+ @Override
+ public StatementContextBase<?,?,?> getParentContext() {
+ return parent;
+ }
+
+ @Override
+ public NamespaceStorageNode getParentNamespaceStorage() {
+ return parent;
+ }
+
+ @Override
+ public Registry getBehaviourRegistry() {
+ return parent.getBehaviourRegistry();
+ }
+
+ @Override
+ public RootStatementContext<?, ?, ?> getRoot() {
+ return parent.getRoot();
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.rfc6020;
+
+import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.global;
+import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.sourceLocal;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+
+public final class YangInferencePipeline {
+
+ public static final StatementSupportBundle LINKAGE_BUNDLE = StatementSupportBundle.builder()
+ .addSupport(new ModuleStatementSupport())
+ .addSupport(new NamespaceStatementImpl.Definition())
+ .addSupport(new ImportStatementDefinition())
+ .addSupport(new PrefixStatementImpl.Definition())
+ .addSupport(global(ModuleNamespace.class))
+ .addSupport(global(NamespaceToModule.class))
+ .addSupport(sourceLocal(ImportedModuleContext.class))
+ .build();
+
+ private static final StatementSupportBundle STMT_DEF_BUNDLE = StatementSupportBundle.derivedFrom(LINKAGE_BUNDLE).build();
+
+ private static final StatementSupportBundle FULL_DECL_BUNDLE = StatementSupportBundle.derivedFrom(STMT_DEF_BUNDLE).build();
+
+ public static final Map<ModelProcessingPhase, StatementSupportBundle> RFC6020_BUNDLES = ImmutableMap
+ .<ModelProcessingPhase, StatementSupportBundle> builder()
+ .put(ModelProcessingPhase.SourceLinkage, LINKAGE_BUNDLE)
+ .put(ModelProcessingPhase.StatementDefinition,STMT_DEF_BUNDLE)
+ .put(ModelProcessingPhase.FullDeclaration,FULL_DECL_BUNDLE)
+ .put(ModelProcessingPhase.EffectiveModel,FULL_DECL_BUNDLE)
+ .build();
+
+ public static final CrossSourceStatementReactor RFC6020_REACTOR = CrossSourceStatementReactor.builder()
+ .setBundle(ModelProcessingPhase.SourceLinkage, LINKAGE_BUNDLE)
+ .setBundle(ModelProcessingPhase.StatementDefinition,STMT_DEF_BUNDLE)
+ .setBundle(ModelProcessingPhase.FullDeclaration,FULL_DECL_BUNDLE)
+ .setBundle(ModelProcessingPhase.EffectiveModel,FULL_DECL_BUNDLE)
+ .build();
+
+ private YangInferencePipeline() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+}
--- /dev/null
+/*
+ * 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.stmt.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+
+public class ImportResolutionTest {
+
+ private static final TestStatementSource ROOT_WITHOUT_IMPORT = new TestStatementSource("nature");
+ private static final TestStatementSource IMPORT_ROOT = new TestStatementSource("mammal","nature");
+ private static final TestStatementSource IMPORT_DERIVED = new TestStatementSource("human", "mammal");
+ private static final TestStatementSource IMPORT_SELF = new TestStatementSource("egocentric", "egocentric");
+ private static final TestStatementSource CICLE_YIN = new TestStatementSource("cycle-yin", "cycle-yang");
+ private static final TestStatementSource CICLE_YANG = new TestStatementSource("cycle-yang", "cycle-yin");
+
+
+ @Test
+ public void inImportOrderTest() throws SourceException, ReactorException {
+ BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ addSources(reactor,ROOT_WITHOUT_IMPORT,IMPORT_ROOT,IMPORT_DERIVED);
+ EffectiveModelContext result = reactor.build();
+ assertNotNull(result);
+ }
+
+ @Test
+ public void inInverseOfImportOrderTest() throws SourceException, ReactorException {
+ BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ addSources(reactor,IMPORT_DERIVED,IMPORT_ROOT,ROOT_WITHOUT_IMPORT);
+ EffectiveModelContext result = reactor.build();
+ assertNotNull(result);
+ }
+
+ @Test
+ public void missingImportedSourceTest() throws SourceException {
+ BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ addSources(reactor,IMPORT_DERIVED,ROOT_WITHOUT_IMPORT);
+ try {
+ reactor.build();
+ fail("reactor.process should fail doe to misssing imported source");
+ } catch (ReactorException e) {
+ assertTrue(e instanceof SomeModifiersUnresolvedException);
+ assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+ }
+
+ }
+
+ @Test
+ public void circularImportsTest() throws SourceException {
+ BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ addSources(reactor,CICLE_YIN,CICLE_YANG);
+ try {
+ reactor.build();
+ fail("reactor.process should fail doe to circular import");
+ } catch (ReactorException e) {
+ assertTrue(e instanceof SomeModifiersUnresolvedException);
+ assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+ }
+ }
+
+ @Test
+ public void selfImportTest() throws SourceException {
+ BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ addSources(reactor,IMPORT_SELF,IMPORT_ROOT,ROOT_WITHOUT_IMPORT);
+ try {
+ reactor.build();
+ fail("reactor.process should fail doe to self import");
+ } catch (ReactorException e) {
+ assertTrue(e instanceof SomeModifiersUnresolvedException);
+ assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+ }
+ }
+
+
+ private void addSources(BuildAction reactor, TestStatementSource... sources) {
+ for(TestStatementSource source : sources) {
+ reactor.addSource(source);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.stmt.test;
+
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Import;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Module;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Namespace;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Prefix;
+
+import java.util.Arrays;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
+
+class TestStatementSource implements StatementStreamSource {
+
+ private static final String NS_PREFIX = "urn:org:opendaylight:yangtools:test:";
+
+ private final String name;
+ private final List<String> imports;
+ private StatementWriter writer;
+ private StatementSourceReference REF = new StatementSourceReference() {
+
+ @Override
+ public StatementSource getStatementSource() {
+ return StatementSource.DECLARATION;
+ }
+ };
+
+
+ public TestStatementSource(String name, String... imports) {
+ this.name = name;
+ this.imports = Arrays.asList(imports);
+ }
+
+ @Override
+ public void writeFull(StatementWriter writer, QNameToStatementDefinition stmtDef, PrefixToModule prefixes)
+ throws SourceException {
+ this.writer = writer;
+ header();
+ extensions();
+ body();
+ end();
+
+ }
+
+
+
+ @Override
+ public void writeLinkage(StatementWriter writer, QNameToStatementDefinition stmtDef) throws SourceException {
+ this.writer = writer;
+ header().end();
+ }
+
+ @Override
+ public void writeLinkageAndStatementDefinitions(StatementWriter writer, QNameToStatementDefinition stmtDef,
+ PrefixToModule prefixes) throws SourceException {
+ this.writer = writer;
+ header();
+ extensions();
+ end();
+
+ }
+
+ protected void extensions() {
+ // TODO Auto-generated method stub
+
+ }
+
+ protected void body() {
+
+ }
+
+ TestStatementSource header() throws SourceException {
+ stmt(Module).arg(name); {
+ stmt(Namespace).arg(getNamespace()).end();
+ stmt(Prefix).arg(name).end();
+ for(String imp : imports) {
+ stmt(Import).arg(imp);
+ stmt(Prefix).arg(imp).end();
+ end();
+ }
+ }
+ return this;
+ }
+
+ private String getNamespace() {
+ return NS_PREFIX + name;
+ }
+
+ protected TestStatementSource arg(String arg) throws SourceException {
+ writer.argumentValue(arg, REF);
+ return this;
+ }
+
+ protected TestStatementSource stmt(Rfc6020Mapping stmt) throws SourceException {
+ writer.startStatement(stmt.getStatementName(), REF);
+ return this;
+ }
+
+ protected TestStatementSource end() throws SourceException {
+ writer.endStatement(REF);
+ return this;
+ }
+
+
+}